From 0c234055bb89c0fe059140a19969ccb65d13198a Mon Sep 17 00:00:00 2001 From: kanoi Date: Mon, 11 Aug 2014 18:08:25 +1000 Subject: [PATCH 01/20] ckdb - split get_data and make all functions allow a DB connection to be passed --- src/ckdb.c | 265 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 152 insertions(+), 113 deletions(-) diff --git a/src/ckdb.c b/src/ckdb.c index 586b729a..20ab608e 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -2853,6 +2853,7 @@ static int64_t workinfo_add(PGconn *conn, char *workinfoidstr, char *poolinstanc char *code, char *inet, tv_t *cd, bool igndup) { ExecStatusType rescode; + bool conned = false; K_TREE_CTX ctx[1]; PGresult *res; K_ITEM *item; @@ -2914,6 +2915,11 @@ static int64_t workinfo_add(PGconn *conn, char *workinfoidstr, char *poolinstanc "prevhash,coinbase1,coinbase2,version,bits,ntime,reward" HISTORYDATECONTROL ") values (" PQPARAM16 ")"; + if (!conn) { + conn = dbconnect(); + conned = true; + } + res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0); rescode = PQresultStatus(res); if (!PGOK(rescode)) { @@ -2925,6 +2931,9 @@ static int64_t workinfo_add(PGconn *conn, char *workinfoidstr, char *poolinstanc unparam: PQclear(res); + if (conned) + PQfinish(conn); + for (n = 0; n < par; n++) free(params[n]); @@ -3271,9 +3280,10 @@ static void zero_sharesummary(SHARESUMMARY *row, tv_t *cd) static K_ITEM *find_sharesummary(int64_t userid, char *workername, int64_t workinfoid); // Memory (and log file) only -static bool shares_add(char *workinfoid, char *username, char *workername, char *clientid, - char *enonce1, char *nonce2, char *nonce, char *diff, char *sdiff, - char *secondaryuserid, char *by, char *code, char *inet, tv_t *cd) +static bool shares_add(PGconn *conn, char *workinfoid, char *username, char *workername, + char *clientid, char *enonce1, char *nonce2, char *nonce, + char *diff, char *sdiff, char *secondaryuserid, char *by, + char *code, char *inet, tv_t *cd) { K_ITEM *s_item, *u_item, *wi_item, *w_item, *ss_item; SHARES *shares; @@ -3311,7 +3321,7 @@ static bool shares_add(char *workinfoid, char *username, char *workername, char if (!wi_item) goto unitem; - w_item = new_default_worker(NULL, false, shares->userid, shares->workername, + w_item = new_default_worker(conn, false, shares->userid, shares->workername, by, code, inet, cd); if (!w_item) goto unitem; @@ -3335,7 +3345,7 @@ static bool shares_add(char *workinfoid, char *username, char *workername, char workerstatus_update(NULL, shares, NULL, NULL); - sharesummary_update(NULL, shares, NULL, NULL, by, code, inet, cd); + sharesummary_update(conn, shares, NULL, NULL, by, code, inet, cd); ok = true; unitem: @@ -3381,9 +3391,10 @@ static cmp_t cmp_shareerrors(K_ITEM *a, K_ITEM *b) // Memory (and log file) only // TODO: handle shareerrors that appear after a workinfoid is aged or doesn't exist? -static bool shareerrors_add(char *workinfoid, char *username, char *workername, - char *clientid, char *errn, char *error, char *secondaryuserid, - char *by, char *code, char *inet, tv_t *cd) +static bool shareerrors_add(PGconn *conn, char *workinfoid, char *username, + char *workername, char *clientid, char *errn, + char *error, char *secondaryuserid, char *by, + char *code, char *inet, tv_t *cd) { K_ITEM *s_item, *u_item, *wi_item, *w_item, *ss_item; SHAREERRORS *shareerrors; @@ -3440,7 +3451,7 @@ static bool shareerrors_add(char *workinfoid, char *username, char *workername, } } - sharesummary_update(NULL, NULL, shareerrors, NULL, by, code, inet, cd); + sharesummary_update(conn, NULL, shareerrors, NULL, by, code, inet, cd); ok = true; unitem: @@ -4365,6 +4376,7 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username, tv_t *cd, bool igndup) { ExecStatusType rescode; + bool conned = false; PGresult *res; K_TREE_CTX ctx[1]; K_ITEM *a_item, *u_item; @@ -4411,6 +4423,11 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username, // Update even if DB fails workerstatus_update(row, NULL, NULL, NULL); + if (conn == NULL) { + conn = dbconnect(); + conned = true; + } + row->authid = nextid(conn, "authid", (int64_t)1, cd, by, code, inet); if (row->authid == 0) goto unitem; @@ -4444,6 +4461,8 @@ unparam: for (n = 0; n < par; n++) free(params[n]); unitem: + if (conned) + PQfinish(conn); K_WLOCK(auths_free); if (!secuserid) k_add_head(auths_free, a_item); @@ -5339,7 +5358,7 @@ static bool check_db_version(PGconn *conn) return true; } -static bool getdata() +static bool getdata1() { PGconn *conn = dbconnect(); bool ok = true; @@ -5350,25 +5369,36 @@ static bool getdata() goto matane; if (!(ok = workers_fill(conn))) goto matane; + ok = auths_fill(conn); + +matane: + + PQfinish(conn); + return ok; +} + +static bool getdata2() +{ + PGconn *conn = dbconnect(); + bool ok = true; + + if (!(ok = blocks_fill(conn))) + goto sukamudai; if (!(ok = payments_fill(conn))) - goto matane; + goto sukamudai; if (!(ok = workinfo_fill(conn))) - goto matane; + goto sukamudai; if (!(ok = shares_fill())) - goto matane; + goto sukamudai; if (!(ok = shareerrors_fill())) - goto matane; + goto sukamudai; if (!(ok = sharesummary_fill(conn))) - goto matane; - if (!(ok = blocks_fill(conn))) - goto matane; - if (!(ok = auths_fill(conn))) - goto matane; + goto sukamudai; if (!(ok = poolstats_fill(conn))) - goto matane; + goto sukamudai; ok = userstats_fill(conn); -matane: +sukamudai: PQfinish(conn); return ok; @@ -5623,7 +5653,10 @@ static bool setup_data() workerstatus_store = k_new_store(workerstatus_free); workerstatus_root = new_ktree(); - if (!getdata()) + if (!getdata1()) + return false; + + if (!getdata2()) return false; db_load_complete = true; @@ -5651,14 +5684,13 @@ static bool setup_data() return true; } -static char *cmd_adduser(char *cmd, char *id, tv_t *now, char *by, char *code, char *inet, - __maybe_unused tv_t *notcd) +static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by, + char *code, char *inet, __maybe_unused tv_t *notcd) { char reply[1024] = ""; size_t siz = sizeof(reply); K_ITEM *i_username, *i_emailaddress, *i_passwordhash; - PGconn *conn; bool ok; LOGDEBUG("%s(): cmd '%s'", __func__, cmd); @@ -5675,12 +5707,10 @@ static char *cmd_adduser(char *cmd, char *id, tv_t *now, char *by, char *code, c if (!i_passwordhash) return strdup(reply); - conn = dbconnect(); ok = users_add(conn, DATA_TRANSFER(i_username)->data, - DATA_TRANSFER(i_emailaddress)->data, - DATA_TRANSFER(i_passwordhash)->data, - now, by, code, inet); - PQfinish(conn); + DATA_TRANSFER(i_emailaddress)->data, + DATA_TRANSFER(i_passwordhash)->data, + now, by, code, inet); if (!ok) { LOGERR("%s.failed.DBE", id); @@ -5691,9 +5721,10 @@ static char *cmd_adduser(char *cmd, char *id, tv_t *now, char *by, char *code, c return strdup(reply); } -static char *cmd_chkpass(char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, - __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) +static char *cmd_chkpass(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, __maybe_unused char *by, + __maybe_unused char *code, __maybe_unused char *inet, + __maybe_unused tv_t *notcd) { K_ITEM *i_username, *i_passwordhash, *u_item; char reply[1024] = ""; @@ -5729,13 +5760,12 @@ static char *cmd_chkpass(char *cmd, char *id, __maybe_unused tv_t *now, __maybe_ return strdup("ok."); } -static char *cmd_poolstats_do(char *cmd, char *id, char *by, char *code, - char *inet, tv_t *cd, bool igndup) +static char *cmd_poolstats_do(PGconn *conn, char *cmd, char *id, char *by, + char *code, char *inet, tv_t *cd, bool igndup) { char reply[1024] = ""; size_t siz = sizeof(reply); K_TREE_CTX ctx[1]; - PGconn *conn; bool store; // log to logfile @@ -5803,7 +5833,6 @@ static char *cmd_poolstats_do(char *cmd, char *id, char *by, char *code, store = false; } - conn = dbconnect(); ok = poolstats_add(conn, store, DATA_TRANSFER(i_poolinstance)->data, DATA_TRANSFER(i_elapsed)->data, DATA_TRANSFER(i_users)->data, @@ -5813,7 +5842,6 @@ static char *cmd_poolstats_do(char *cmd, char *id, char *by, char *code, DATA_TRANSFER(i_hashrate1hr)->data, DATA_TRANSFER(i_hashrate24hr)->data, by, code, inet, cd, igndup); - PQfinish(conn); if (!ok) { LOGERR("%s.failed.DBE", id); @@ -5824,8 +5852,9 @@ static char *cmd_poolstats_do(char *cmd, char *id, char *by, char *code, return strdup(reply); } -static char *cmd_poolstats(char *cmd, char *id, __maybe_unused tv_t *notnow, - char *by, char *code, char *inet, tv_t *cd) +static char *cmd_poolstats(PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *notnow, char *by, + char *code, char *inet, tv_t *cd) { bool igndup = false; @@ -5836,11 +5865,12 @@ static char *cmd_poolstats(char *cmd, char *id, __maybe_unused tv_t *notnow, return NULL; } - return cmd_poolstats_do(cmd, id, by, code, inet, cd, igndup); + return cmd_poolstats_do(conn, cmd, id, by, code, inet, cd, igndup); } -static char *cmd_userstats(char *cmd, char *id, __maybe_unused tv_t *notnow, - char *by, char *code, char *inet, tv_t *cd) +static char *cmd_userstats(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *notnow, char *by, char *code, + char *inet, tv_t *cd) { char reply[1024] = ""; size_t siz = sizeof(reply); @@ -5917,8 +5947,8 @@ static char *cmd_userstats(char *cmd, char *id, __maybe_unused tv_t *notnow, return strdup(reply); } -static char *cmd_newid(char *cmd, char *id, tv_t *now, char *by, char *code, char *inet, - __maybe_unused tv_t *cd) +static char *cmd_newid(PGconn *conn, char *cmd, char *id, tv_t *now, char *by, + char *code, char *inet, __maybe_unused tv_t *cd) { char reply[1024] = ""; size_t siz = sizeof(reply); @@ -5928,8 +5958,8 @@ static char *cmd_newid(char *cmd, char *id, tv_t *now, char *by, char *code, cha int par; bool ok = false; ExecStatusType rescode; + bool conned = false; PGresult *res; - PGconn *conn; char *ins; int n; @@ -5962,7 +5992,10 @@ static char *cmd_newid(char *cmd, char *id, tv_t *now, char *by, char *code, cha ins = "insert into idcontrol " "(idname,lastid" MODIFYDATECONTROL ") values (" PQPARAM10 ")"; - conn = dbconnect(); + if (!conn) { + conn = dbconnect(); + conned = true; + } res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0); rescode = PQresultStatus(res); @@ -5974,7 +6007,8 @@ static char *cmd_newid(char *cmd, char *id, tv_t *now, char *by, char *code, cha ok = true; foil: PQclear(res); - PQfinish(conn); + if (conned) + PQfinish(conn); for (n = 0; n < par; n++) free(params[n]); @@ -5992,9 +6026,10 @@ foil: return strdup(reply); } -static char *cmd_payments(char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, - __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) +static char *cmd_payments(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, __maybe_unused char *by, + __maybe_unused char *code, __maybe_unused char *inet, + __maybe_unused tv_t *notcd) { K_ITEM *i_username, look, *u_item, *p_item; K_TREE_CTX ctx[1]; @@ -6047,9 +6082,10 @@ static char *cmd_payments(char *cmd, char *id, __maybe_unused tv_t *now, __maybe return buf; } -static char *cmd_workers(char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, - __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) +static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, __maybe_unused char *by, + __maybe_unused char *code, __maybe_unused char *inet, + __maybe_unused tv_t *notcd) { K_ITEM *i_username, *i_stats, wlook, *u_item, *w_item, uslook, *us_item, *ws_item; K_TREE_CTX w_ctx[1], us_ctx[1]; @@ -6184,9 +6220,10 @@ static char *cmd_workers(char *cmd, char *id, __maybe_unused tv_t *now, __maybe_ return buf; } -static char *cmd_allusers(char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, - __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) +static char *cmd_allusers(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, __maybe_unused char *by, + __maybe_unused char *code, __maybe_unused char *inet, + __maybe_unused tv_t *notcd) { K_TREE *userstats_workername_root = new_ktree(); K_ITEM *us_item, *usw_item, *tmp_item, *u_item; @@ -6289,12 +6326,12 @@ static char *cmd_allusers(char *cmd, char *id, __maybe_unused tv_t *now, __maybe return buf; } -static char *cmd_sharelog(char *cmd, char *id, __maybe_unused tv_t *notnow, - char *by, char *code, char *inet, tv_t *cd) +static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *notnow, char *by, + char *code, char *inet, tv_t *cd) { char reply[1024] = ""; size_t siz = sizeof(reply); - PGconn *conn; // log to logfile with processing success/failure code @@ -6358,7 +6395,6 @@ static char *cmd_sharelog(char *cmd, char *id, __maybe_unused tv_t *notnow, if (!i_reward) return strdup(reply); - conn = dbconnect(); workinfoid = workinfo_add(conn, DATA_TRANSFER(i_workinfoid)->data, DATA_TRANSFER(i_poolinstance)->data, DATA_TRANSFER(i_transactiontree)->data, @@ -6371,7 +6407,6 @@ static char *cmd_sharelog(char *cmd, char *id, __maybe_unused tv_t *notnow, DATA_TRANSFER(i_ntime)->data, DATA_TRANSFER(i_reward)->data, by, code, inet, cd, igndup); - PQfinish(conn); if (workinfoid == -1) { LOGERR("%s.failed.DBE", id); @@ -6431,17 +6466,17 @@ static char *cmd_sharelog(char *cmd, char *id, __maybe_unused tv_t *notnow, if (!i_secondaryuserid) return strdup(reply); - ok = shares_add(DATA_TRANSFER(i_workinfoid)->data, - DATA_TRANSFER(i_username)->data, - DATA_TRANSFER(i_workername)->data, - DATA_TRANSFER(i_clientid)->data, - DATA_TRANSFER(i_enonce1)->data, - DATA_TRANSFER(i_nonce2)->data, - DATA_TRANSFER(i_nonce)->data, - DATA_TRANSFER(i_diff)->data, - DATA_TRANSFER(i_sdiff)->data, - DATA_TRANSFER(i_secondaryuserid)->data, - by, code, inet, cd); + ok = shares_add(conn, DATA_TRANSFER(i_workinfoid)->data, + DATA_TRANSFER(i_username)->data, + DATA_TRANSFER(i_workername)->data, + DATA_TRANSFER(i_clientid)->data, + DATA_TRANSFER(i_enonce1)->data, + DATA_TRANSFER(i_nonce2)->data, + DATA_TRANSFER(i_nonce)->data, + DATA_TRANSFER(i_diff)->data, + DATA_TRANSFER(i_sdiff)->data, + DATA_TRANSFER(i_secondaryuserid)->data, + by, code, inet, cd); if (!ok) { LOGERR("%s.failed.DATA", id); @@ -6489,14 +6524,14 @@ static char *cmd_sharelog(char *cmd, char *id, __maybe_unused tv_t *notnow, if (!i_secondaryuserid) return strdup(reply); - ok = shareerrors_add(DATA_TRANSFER(i_workinfoid)->data, - DATA_TRANSFER(i_username)->data, - DATA_TRANSFER(i_workername)->data, - DATA_TRANSFER(i_clientid)->data, - DATA_TRANSFER(i_errn)->data, - DATA_TRANSFER(i_error)->data, - DATA_TRANSFER(i_secondaryuserid)->data, - by, code, inet, cd); + ok = shareerrors_add(conn, DATA_TRANSFER(i_workinfoid)->data, + DATA_TRANSFER(i_username)->data, + DATA_TRANSFER(i_workername)->data, + DATA_TRANSFER(i_clientid)->data, + DATA_TRANSFER(i_errn)->data, + DATA_TRANSFER(i_error)->data, + DATA_TRANSFER(i_secondaryuserid)->data, + by, code, inet, cd); if (!ok) { LOGERR("%s.failed.DATA", id); return strdup("failed.DATA"); @@ -6521,7 +6556,7 @@ static char *cmd_sharelog(char *cmd, char *id, __maybe_unused tv_t *notnow, if (!i_poolinstance) return strdup(reply); - ok = workinfo_age(NULL, DATA_TRANSFER(i_workinfoid)->data, + ok = workinfo_age(conn, DATA_TRANSFER(i_workinfoid)->data, DATA_TRANSFER(i_poolinstance)->data, by, code, inet, cd); @@ -6543,12 +6578,11 @@ static char *cmd_sharelog(char *cmd, char *id, __maybe_unused tv_t *notnow, } // TODO: the confirm update: identify block changes from workinfo height? -static char *cmd_blocks_do(char *cmd, char *id, char *by, char *code, char *inet, - tv_t *cd, bool igndup) +static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by, + char *code, char *inet, tv_t *cd, bool igndup) { char reply[1024] = ""; size_t siz = sizeof(reply); - PGconn *conn; K_ITEM *i_height, *i_blockhash, *i_confirmed, *i_workinfoid, *i_username; K_ITEM *i_workername, *i_clientid, *i_enonce1, *i_nonce2, *i_nonce, *i_reward; char *msg; @@ -6604,7 +6638,6 @@ static char *cmd_blocks_do(char *cmd, char *id, char *by, char *code, char *inet return strdup(reply); msg = "added"; - conn = dbconnect(); ok = blocks_add(conn, DATA_TRANSFER(i_height)->data, DATA_TRANSFER(i_blockhash)->data, DATA_TRANSFER(i_confirmed)->data, @@ -6620,7 +6653,6 @@ static char *cmd_blocks_do(char *cmd, char *id, char *by, char *code, char *inet break; case BLOCKS_CONFIRM: msg = "confirmed"; - conn = dbconnect(); ok = blocks_add(conn, DATA_TRANSFER(i_height)->data, DATA_TRANSFER(i_blockhash)->data, DATA_TRANSFER(i_confirmed)->data, @@ -6634,8 +6666,6 @@ static char *cmd_blocks_do(char *cmd, char *id, char *by, char *code, char *inet return strdup("failed.DATA"); } - PQfinish(conn); - if (!ok) { LOGERR("%s.failed.DBE", id); return strdup("failed.DBE"); @@ -6646,8 +6676,9 @@ static char *cmd_blocks_do(char *cmd, char *id, char *by, char *code, char *inet return strdup(reply); } -static char *cmd_blocks(char *cmd, char *id, __maybe_unused tv_t *notnow, - char *by, char *code, char *inet, tv_t *cd) +static char *cmd_blocks(PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *notnow, char *by, + char *code, char *inet, tv_t *cd) { bool igndup = false; @@ -6658,15 +6689,14 @@ static char *cmd_blocks(char *cmd, char *id, __maybe_unused tv_t *notnow, return NULL; } - return cmd_blocks_do(cmd, id, by, code, inet, cd, igndup); + return cmd_blocks_do(conn, cmd, id, by, code, inet, cd, igndup); } -static char *cmd_auth_do(char *cmd, char *id, __maybe_unused tv_t *now, char *by, +static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by, char *code, char *inet, tv_t *cd, bool igndup) { char reply[1024] = ""; size_t siz = sizeof(reply); - PGconn *conn; K_ITEM *i_poolinstance, *i_username, *i_workername, *i_clientid; K_ITEM *i_enonce1, *i_useragent; char *secuserid; @@ -6697,7 +6727,6 @@ static char *cmd_auth_do(char *cmd, char *id, __maybe_unused tv_t *now, char *by if (!i_useragent) return strdup(reply); - conn = dbconnect(); secuserid = auths_add(conn, DATA_TRANSFER(i_poolinstance)->data, DATA_TRANSFER(i_username)->data, DATA_TRANSFER(i_workername)->data, @@ -6705,7 +6734,6 @@ static char *cmd_auth_do(char *cmd, char *id, __maybe_unused tv_t *now, char *by DATA_TRANSFER(i_enonce1)->data, DATA_TRANSFER(i_useragent)->data, by, code, inet, cd, igndup); - PQfinish(conn); if (!secuserid) { LOGDEBUG("%s.failed.DBE", id); @@ -6717,8 +6745,9 @@ static char *cmd_auth_do(char *cmd, char *id, __maybe_unused tv_t *now, char *by return strdup(reply); } -static char *cmd_auth(char *cmd, char *id, tv_t *now, char *by, - char *code, char *inet, tv_t *cd) +static char *cmd_auth(PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, char *by, + char *code, char *inet, tv_t *cd) { bool igndup = false; @@ -6729,12 +6758,13 @@ static char *cmd_auth(char *cmd, char *id, tv_t *now, char *by, return NULL; } - return cmd_auth_do(cmd, id, now, by, code, inet, cd, igndup); + return cmd_auth_do(conn, cmd, id, by, code, inet, cd, igndup); } -static char *cmd_homepage(char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, - __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) +static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, __maybe_unused char *by, + __maybe_unused char *code, __maybe_unused char *inet, + __maybe_unused tv_t *notcd) { K_ITEM *i_username, *u_item, *b_item, *p_item, *us_item, look; double u_hashrate5m, u_hashrate1hr; @@ -6868,9 +6898,10 @@ static char *cmd_homepage(char *cmd, char *id, __maybe_unused tv_t *now, __maybe return buf; } -static char *cmd_dsp(char *cmd, char *id, __maybe_unused tv_t *now, - __maybe_unused char *by, __maybe_unused char *code, - __maybe_unused char *inet, __maybe_unused tv_t *notcd) +static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd, + char *id, __maybe_unused tv_t *now, + __maybe_unused char *by, __maybe_unused char *code, + __maybe_unused char *inet, __maybe_unused tv_t *notcd) { __maybe_unused K_ITEM *i_file; __maybe_unused char reply[1024] = ""; @@ -6897,9 +6928,10 @@ static char *cmd_dsp(char *cmd, char *id, __maybe_unused tv_t *now, */ } -static char *cmd_stats(char *cmd, char *id, __maybe_unused tv_t *now, - __maybe_unused char *by, __maybe_unused char *code, - __maybe_unused char *inet, __maybe_unused tv_t *notcd) +static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, __maybe_unused char *by, + __maybe_unused char *code, __maybe_unused char *inet, + __maybe_unused tv_t *notcd) { char tmp[1024], *buf; size_t len, off; @@ -6987,7 +7019,7 @@ static struct CMDS { char *cmd_str; bool noid; // doesn't require an id bool createdate; // requires a createdate - char *(*func)(char *, char *, tv_t *, char *, char *, char *, tv_t *); + char *(*func)(PGconn *, char *, char *, tv_t *, char *, char *, char *, tv_t *); char *access; } cmds[] = { { CMD_SHUTDOWN, "shutdown", true, false, NULL, ACCESS_SYSTEM }, @@ -7425,7 +7457,7 @@ static void *summariser(__maybe_unused void *arg) return NULL; } -static void reload_line(char *filename, uint64_t count, char *buf) +static void reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) { char cmd[CMD_SIZ+1], id[ID_SIZ+1]; enum cmd_values cmdnum; @@ -7475,7 +7507,8 @@ static void reload_line(char *filename, uint64_t count, char *buf) case CMD_POOLSTAT: case CMD_USERSTAT: case CMD_BLOCK: - ans = cmds[which_cmds].func(cmd, id, &now, (char *)"code", + ans = cmds[which_cmds].func(conn, cmd, id, &now, + (char *)"code", (char *)__func__, (char *)"127.0.0.1", &cd); if (ans) @@ -7513,6 +7546,7 @@ static void reload_line(char *filename, uint64_t count, char *buf) * when ckdb aborts at the beginning of the reload */ static void reload_from(tv_t *start) { + PGconn *conn = NULL; char buf[DATE_BUFSIZ+1], run[DATE_BUFSIZ+1]; size_t rflen = strlen(restorefrom); char *missingfirst = NULL, *missinglast = NULL; @@ -7540,6 +7574,8 @@ static void reload_from(tv_t *start) snprintf(data, sizeof(data), "reload.%s.s0", run); LOGFILE(data); + conn = dbconnect(); + total = 0; processing = 0; while (!finished) { @@ -7548,7 +7584,7 @@ static void reload_from(tv_t *start) count = 0; while (fgets_unlocked(data, MAX_READ, fp)) - reload_line(filename, ++count, data); + reload_line(conn, filename, ++count, data); if (ferror(fp)) { int err = errno; @@ -7609,6 +7645,8 @@ static void reload_from(tv_t *start) } } + PQfinish(conn); + snprintf(data, sizeof(data), "reload.%s.%"PRIu64, run, total); LOGFILE(data); LOGWARNING("%s(): read %d file%s, total %"PRIu64" line%s", @@ -7734,7 +7772,8 @@ static void *listener(void *arg) if (dup) send_unix_msg(sockd, last_reply); else { - ans = cmds[which_cmds].func(cmd, id, &now, (char *)"code", + ans = cmds[which_cmds].func(NULL, cmd, id, &now, + (char *)"code", (char *)__func__, (char *)"127.0.0.1", &cd); siz = strlen(ans) + strlen(id) + 32; From 48a891372cce21758a35105f6db07045ad9f6acd Mon Sep 17 00:00:00 2001 From: kanoi Date: Mon, 11 Aug 2014 18:16:45 +1000 Subject: [PATCH 02/20] ckdb - poolstats needs to check conn --- src/ckdb.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ckdb.c b/src/ckdb.c index 20ab608e..d21d941e 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -4614,6 +4614,7 @@ static bool poolstats_add(PGconn *conn, bool store, char *poolinstance, bool igndup) { ExecStatusType rescode; + bool conned = false; PGresult *res; K_TREE_CTX ctx[1]; K_ITEM *p_item; @@ -4671,6 +4672,11 @@ static bool poolstats_add(PGconn *conn, bool store, char *poolinstance, "hashrate5m,hashrate1hr,hashrate24hr" SIMPLEDATECONTROL ") values (" PQPARAM12 ")"; + if (!conn) { + conn = dbconnect(); + conned = true; + } + res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0); rescode = PQresultStatus(res); if (!PGOK(rescode)) { @@ -4685,6 +4691,8 @@ static bool poolstats_add(PGconn *conn, bool store, char *poolinstance, unparam: if (store) { PQclear(res); + if (conned) + PQfinish(conn); for (n = 0; n < par; n++) free(params[n]); } From e2ab8603da9591fd45d7054a9825d299d9955df0 Mon Sep 17 00:00:00 2001 From: kanoi Date: Tue, 12 Aug 2014 00:51:26 +1000 Subject: [PATCH 03/20] php - fix registration breakage --- pool/base.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pool/base.php b/pool/base.php index 8903293d..97211a63 100644 --- a/pool/base.php +++ b/pool/base.php @@ -229,7 +229,7 @@ function validate() $whoid = ''; if (!isset($_SESSION['ckpkey'])) - return false; + return array(false, NULL); $key = $_SESSION['ckpkey']; if (!isset($_SESSION[$key])) From 095402b069ba4c197b4ed2238e00d962ef416624 Mon Sep 17 00:00:00 2001 From: kanoi Date: Tue, 12 Aug 2014 00:56:43 +1000 Subject: [PATCH 04/20] ckdb - fix nextid breakage --- src/ckdb.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ckdb.c b/src/ckdb.c index d21d941e..1f527027 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -1742,6 +1742,7 @@ static int64_t nextid(PGconn *conn, char *idname, int64_t increment, tv_t *cd, char *by, char *code, char *inet) { ExecStatusType rescode; + bool conned = false; PGresult *res; char qry[1024]; char *params[5]; @@ -1757,6 +1758,11 @@ static int64_t nextid(PGconn *conn, char *idname, int64_t increment, "where idname='%s' for update", idname); + if (conn == NULL) { + conn = dbconnect(); + conned = true; + } + res = PQexec(conn, qry); rescode = PQresultStatus(res); if (!PGOK(rescode)) { @@ -1811,6 +1817,8 @@ static int64_t nextid(PGconn *conn, char *idname, int64_t increment, free(params[n]); cleanup: PQclear(res); + if (conned) + PQfinish(conn); return lastid; } From 1619b9b159ad0ccd4a41fd95d4610aa1a0dbd0b3 Mon Sep 17 00:00:00 2001 From: kanoi Date: Tue, 12 Aug 2014 01:15:57 +1000 Subject: [PATCH 05/20] ckdb - ensure a DB connection is always initiated before use --- src/ckdb.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/ckdb.c b/src/ckdb.c index 1f527027..bd38d44a 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -2024,6 +2024,7 @@ static bool users_add(PGconn *conn, char *username, char *emailaddress, char *pa tv_t *now, char *by, char *code, char *inet) { ExecStatusType rescode; + bool conned = false; PGresult *res; K_ITEM *item; int n; @@ -2080,6 +2081,11 @@ static bool users_add(PGconn *conn, char *username, char *emailaddress, char *pa "secondaryuserid" HISTORYDATECONTROL ") values (" PQPARAM11 ")"; + if (!conn) { + conn = dbconnect(); + conned = true; + } + res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0); rescode = PQresultStatus(res); if (!PGOK(rescode)) { @@ -2090,6 +2096,8 @@ static bool users_add(PGconn *conn, char *username, char *emailaddress, char *pa ok = true; unparam: PQclear(res); + if (conned) + PQfinish(conn); for (n = 0; n < par; n++) free(params[n]); unitem: @@ -2253,6 +2261,7 @@ static K_ITEM *workers_add(PGconn *conn, int64_t userid, char *workername, char *code, char *inet, tv_t *cd) { ExecStatusType rescode; + bool conned = false; PGresult *res; K_ITEM *item, *ret = NULL; int n; @@ -2271,6 +2280,11 @@ static K_ITEM *workers_add(PGconn *conn, int64_t userid, char *workername, row = DATA_WORKERS(item); + if (conn == NULL) { + conn = dbconnect(); + conned = true; + } + row->workerid = nextid(conn, "workerid", (int64_t)1, cd, by, code, inet); if (row->workerid == 0) goto unitem; @@ -2337,6 +2351,8 @@ unparam: for (n = 0; n < par; n++) free(params[n]); unitem: + if (conned) + PQfinish(conn); K_WLOCK(workers_free); if (!ret) k_add_head(workers_free, item); @@ -2354,6 +2370,7 @@ static bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault, char *by, char *code, char *inet, tv_t *cd) { ExecStatusType rescode; + bool conned = false; PGresult *res; int n; WORKERS *row; @@ -2410,6 +2427,11 @@ static bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault, params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0); PARCHKVAL(par, 3, params); + if (conn == NULL) { + conn = dbconnect(); + conned = true; + } + res = PQexec(conn, "Begin"); rescode = PQresultStatus(res); if (!PGOK(rescode)) { @@ -2465,6 +2487,8 @@ static bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault, ok = true; unparam: PQclear(res); + if (conned) + PQfinish(conn); for (n = 0; n < par; n++) free(params[n]); early: @@ -2941,7 +2965,6 @@ unparam: PQclear(res); if (conned) PQfinish(conn); - for (n = 0; n < par; n++) free(params[n]); @@ -4061,6 +4084,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, bool igndup, char *id) { ExecStatusType rescode; + bool conned = false; PGresult *res = NULL; K_TREE_CTX ctx[1]; K_ITEM *item, *u_item; @@ -4130,6 +4154,11 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, "clientid,enonce1,nonce2,nonce,reward,confirmed" HISTORYDATECONTROL ") values (" PQPARAM16 ")"; + if (conn == NULL) { + conn = dbconnect(); + conned = true; + } + res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0); rescode = PQresultStatus(res); if (!PGOK(rescode)) { @@ -4146,6 +4175,11 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0); PARCHKVAL(par, 3, params); + if (conn == NULL) { + conn = dbconnect(); + conned = true; + } + res = PQexec(conn, "Begin"); rescode = PQresultStatus(res); if (!PGOK(rescode)) { @@ -4205,6 +4239,9 @@ unparam: for (n = 0; n < par; n++) free(params[n]); flail: + if (conned) + PQfinish(conn); + K_WLOCK(blocks_free); if (!ok) k_add_head(blocks_free, item); @@ -4944,6 +4981,7 @@ static cmp_t cmp_userstats_workerstatus(K_ITEM *a, K_ITEM *b) static bool userstats_add_db(PGconn *conn, USERSTATS *row) { ExecStatusType rescode; + bool conned = false; PGresult *res; char *ins; bool ok = false; @@ -4972,6 +5010,11 @@ static bool userstats_add_db(PGconn *conn, USERSTATS *row) "hashrate24hr,summarylevel,summarycount,statsdate" SIMPLEDATECONTROL ") values (" PQPARAM14 ")"; + if (conn == NULL) { + conn = dbconnect(); + conned = true; + } + res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0); rescode = PQresultStatus(res); if (!PGOK(rescode)) { @@ -4982,6 +5025,8 @@ static bool userstats_add_db(PGconn *conn, USERSTATS *row) ok = true; unparam: PQclear(res); + if (conned) + PQfinish(conn); for (n = 0; n < par; n++) free(params[n]); From 43d8ab3b1eeea7852d1aa5362c91510c24022d14 Mon Sep 17 00:00:00 2001 From: kanoi Date: Tue, 12 Aug 2014 01:25:29 +1000 Subject: [PATCH 06/20] php - describe 'safe' --- pool/page_reg.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pool/page_reg.php b/pool/page_reg.php index 5a97f3a4..7b7345da 100644 --- a/pool/page_reg.php +++ b/pool/page_reg.php @@ -96,7 +96,7 @@ function show_reg($menu, $name, $u) if ($pass === NULL || safepass($pass) !== true) { $ok = false; - $data['error'] = "Password is unsafe"; + $data['error'] = "Password is unsafe - requires 6 or more chars, including upper+lower+digits"; } elseif ($pass2 === NULL || $pass2 != $pass) { $ok = false; From 647fe51a2048227f8579b4582d23283c7018b089 Mon Sep 17 00:00:00 2001 From: kanoi Date: Tue, 12 Aug 2014 01:53:05 +1000 Subject: [PATCH 07/20] php - align hash rates better --- pool/page_workers.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pool/page_workers.php b/pool/page_workers.php index 86e10e6c..83c5da01 100644 --- a/pool/page_workers.php +++ b/pool/page_workers.php @@ -82,10 +82,15 @@ function doworker($data, $user) else { $uhr /= 10000000; - if ($uhr < 100000) - $uhr = (round($uhr)/100).'GHs'; + if ($uhr < 0.01) + $uhr = '0GHs'; else - $uhr = (round($uhr/1000)/100).'THs'; + { + if ($uhr < 100000) + $uhr = number_format(round($uhr)/100,2).'GHs'; + else + $uhr = number_format(round($uhr/1000)/100,2).'THs'; + } } $pg .= "$uhr"; $pg .= "\n"; From 0fb34986dddd989bda15f413e7938d289ccddceb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 12 Aug 2014 10:43:42 +1000 Subject: [PATCH 08/20] Abandon trying to mix delayed sends with new ones, instead adding them to a separate linked list and always polling every 100ms --- src/connector.c | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/connector.c b/src/connector.c index 4cbe5b6f..bcd15ef4 100644 --- a/src/connector.c +++ b/src/connector.c @@ -71,14 +71,13 @@ struct sender_send { client_instance_t *client; char *buf; int len; - bool polling; - ts_t polltime; }; typedef struct sender_send sender_send_t; /* For the linked list of pending sends */ static sender_send_t *sender_sends; +static sender_send_t *delayed_sends; /* For protecting the pending sends list */ static pthread_mutex_t sender_lock; @@ -335,34 +334,30 @@ void *sender(void *arg) sender_send_t *sender_send; client_instance_t *client; int ret, fd, ofs = 0; - bool polling = false; mutex_lock(&sender_lock); - if (sender_sends && sender_sends->polling) - polling = true; - if (!sender_sends || polling) { + /* Poll every 100ms if there are no new sends */ + if (!sender_sends) { + const ts_t polltime = {0, 100000000}; ts_t timeout_ts; - if (!polling) { - /* Wait 1 second in pure event driven mode */ - ts_realtime(&timeout_ts); - timeout_ts.tv_sec += 1; - } else { - /* Poll every 100ms if the head of the list is - * a delayed writer. */ - timeout_ts.tv_sec = 0; - timeout_ts.tv_nsec = 100000000; - timeraddspec(&timeout_ts, &sender_sends->polltime); - } + ts_realtime(&timeout_ts); + timeraddspec(&timeout_ts, &polltime); pthread_cond_timedwait(&sender_cond, &sender_lock, &timeout_ts); } sender_send = sender_sends; - if (likely(sender_send)) + if (sender_send) DL_DELETE(sender_sends, sender_send); mutex_unlock(&sender_lock); - if (!sender_send) - continue; + /* Service delayed sends only if we have timed out on the + * conditional with no new sends appearing. */ + if (!sender_send) { + if (!delayed_sends) + continue; + sender_send = delayed_sends; + DL_DELETE(delayed_sends, sender_send); + } client = sender_send->client; @@ -390,13 +385,10 @@ void *sender(void *arg) } LOGDEBUG("Client %d not ready for writes", client->id); - /* Append it to the tail of the list */ - mutex_lock(&sender_lock); - DL_APPEND(sender_sends, sender_send); - mutex_unlock(&sender_lock); - - sender_send->polling = true; - ts_realtime(&sender_send->polltime); + /* Append it to the tail of the delayed sends list. + * This is the only function that alters it so no + * locking is required. */ + DL_APPEND(delayed_sends, sender_send); continue; } while (sender_send->len) { From 03706ed5b2af4eaeb72ae1fc0d58f185fad272f7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 12 Aug 2014 18:06:18 +1000 Subject: [PATCH 09/20] Only add the handover parameter on restart if it's not already set --- src/ckpool.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ckpool.c b/src/ckpool.c index b4828e33..77bf20cf 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -275,8 +275,10 @@ retry: LOGWARNING("Failed to send_procmsg to connector"); } else if (cmdmatch(buf, "restart")) { if (!fork()) { - ckp->initial_args[ckp->args++] = strdup("-H"); - ckp->initial_args[ckp->args] = NULL; + if (!ckp->handover) { + ckp->initial_args[ckp->args++] = strdup("-H"); + ckp->initial_args[ckp->args] = NULL; + } execv(ckp->initial_args[0], (char *const *)ckp->initial_args); } } else { From 7daa709781a3e592f11792aa8174a57281a2a0d8 Mon Sep 17 00:00:00 2001 From: kanoi Date: Wed, 13 Aug 2014 16:24:43 +1000 Subject: [PATCH 10/20] libckpool - add semaphone function set as cksum_* --- src/libckpool.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ src/libckpool.h | 13 +++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/libckpool.c b/src/libckpool.c index dd0bd1c4..572c860c 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -258,6 +258,67 @@ void _ck_wunlock(cklock_t *lock, const char *file, const char *func, const int l _mutex_unlock(&lock->mutex, file, func, line); } +void _cksem_init(sem_t *sem, const char *file, const char *func, const int line) +{ + int ret; + if ((ret = sem_init(sem, 0, 0))) + quitfrom(1, file, func, line, "Failed to sem_init ret=%d errno=%d", ret, errno); +} + +void _cksem_post(sem_t *sem, const char *file, const char *func, const int line) +{ + if (unlikely(sem_post(sem))) + quitfrom(1, file, func, line, "Failed to sem_post errno=%d sem=0x%p", errno, sem); +} + +void _cksem_wait(sem_t *sem, const char *file, const char *func, const int line) +{ +retry: + if (unlikely(sem_wait(sem))) { + if (errno == EINTR) + goto retry; + quitfrom(1, file, func, line, "Failed to sem_wait errno=%d sem=0x%p", errno, sem); + } +} + +int _cksem_mswait(sem_t *sem, int ms, const char *file, const char *func, const int line) +{ + ts_t abs_timeout, ts_now; + tv_t tv_now; + int ret; + + tv_time(&tv_now); + tv_to_ts(&ts_now, &tv_now); + ms_to_ts(&abs_timeout, ms); +retry: + timeraddspec(&abs_timeout, &ts_now); + ret = sem_timedwait(sem, &abs_timeout); + + if (ret) { + if (likely(errno == ETIMEDOUT)) + return ETIMEDOUT; + if (errno == EINTR) + goto retry; + quitfrom(1, file, func, line, "Failed to sem_timedwait errno=%d sem=0x%p", errno, sem); + } + return 0; +} + +void cksem_reset(sem_t *sem) +{ + int ret; + + do { + ret = sem_trywait(sem); + if (unlikely(ret < 0 && (errno == EINTR))) + ret = 0; + } while (!ret); +} + +void cksem_destroy(sem_t *sem) +{ + sem_destroy(sem); +} bool extract_sockaddr(char *url, char **sockaddr_url, char **sockaddr_port) { diff --git a/src/libckpool.h b/src/libckpool.h index c59b24f7..b3251370 100644 --- a/src/libckpool.h +++ b/src/libckpool.h @@ -21,6 +21,7 @@ #include #include #include +#include #if HAVE_BYTESWAP_H # include @@ -356,6 +357,18 @@ void _ck_dlock(cklock_t *lock, const char *file, const char *func, const int lin void _ck_runlock(cklock_t *lock, const char *file, const char *func, const int line); void _ck_wunlock(cklock_t *lock, const char *file, const char *func, const int line); +void _cksem_init(sem_t *sem, const char *file, const char *func, const int line); +void _cksem_post(sem_t *sem, const char *file, const char *func, const int line); +void _cksem_wait(sem_t *sem, const char *file, const char *func, const int line); +int _cksem_mswait(sem_t *sem, int ms, const char *file, const char *func, const int line); +void cksem_reset(sem_t *sem); +void cksem_destroy(sem_t *sem); + +#define cksem_init(_sem) _cksem_init(_sem, __FILE__, __func__, __LINE__) +#define cksem_post(_sem) _cksem_post(_sem, __FILE__, __func__, __LINE__) +#define cksem_wait(_sem) _cksem_wait(_sem, __FILE__, __func__, __LINE__) +#define cksem_mswait(_sem, _timeout) _cksem_mswait(_sem, _timeout, __FILE__, __func__, __LINE__) + static inline bool sock_connecting(void) { return errno == EINPROGRESS; From 4e5e17343dabd05e6ad96a78a8de1643a8829467 Mon Sep 17 00:00:00 2001 From: kanoi Date: Wed, 13 Aug 2014 17:00:34 +1000 Subject: [PATCH 11/20] php - add a partial timestamp to the outgoing id --- pool/db.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pool/db.php b/pool/db.php index 6ec73703..14a939c3 100644 --- a/pool/db.php +++ b/pool/db.php @@ -50,7 +50,8 @@ function msgEncode($cmd, $id, $fields) { global $send_sep, $fld_sep, $val_sep; - $msg = $cmd . $send_sep . $id; + $t = time() % 10000; + $msg = $cmd . $send_sep . $id.$t; $first = true; foreach ($fields as $name => $value) { From 690561793228ec1fc3b1f2b34483e3ae72a5e6ca Mon Sep 17 00:00:00 2001 From: kanoi Date: Thu, 14 Aug 2014 21:38:02 +1000 Subject: [PATCH 12/20] ckdb - allow critical messages before dbload completes and reload starts --- src/ckdb.c | 1088 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 731 insertions(+), 357 deletions(-) diff --git a/src/ckdb.c b/src/ckdb.c index bd38d44a..005da811 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -41,7 +41,8 @@ * to ensure all code using those trees/lists use locks * This code's lock implementation is equivalent to table level locking * Consider adding row level locking (a per kitem usage count) if needed - * */ + * TODO: verify all tables with multuthread access are locked + */ #define DB_VLOCK "1" #define DB_VERSION "0.6" @@ -102,11 +103,11 @@ static char *restorefrom; * in the CCLs and thus where to stop processing the CCLs to stay in * sync with ckpool * If ckpool isn't running, then the reload will complete at the end of - * the last CCL file, however if a message arrives from ckpool while + * the last CCL file, however if the 1st message arrives from ckpool while * processing the CCLs, that will mark the point where to stop processing * but can also produce a fatal error at the end of processing, reporting - * the full ckpool message, if the message was not found in the CCL - * processing after the message was received + * the ckpool message, if the message was not found in the CCL processing + * after the message was received * This can be caused by two circumstances: * 1) the disk had not yet written it to the CCL when ckdb read EOF and * ckpool was started at about the same time as the reload completed. @@ -416,15 +417,15 @@ static const tv_t date_begin = { DATE_BEGIN, 0L }; } while (0) // Override _row defaults if transfer fields are present -#define HISTORYDATETRANSFER(_row) do { \ +#define HISTORYDATETRANSFER(_root, _row) do { \ K_ITEM *item; \ - item = optional_name("createby", 1, NULL); \ + item = optional_name(_root, "createby", 1, NULL); \ if (item) \ STRNCPY(_row->createby, DATA_TRANSFER(item)->data); \ - item = optional_name("createcode", 1, NULL); \ + item = optional_name(_root, "createcode", 1, NULL); \ if (item) \ STRNCPY(_row->createcode, DATA_TRANSFER(item)->data); \ - item = optional_name("createinet", 1, NULL); \ + item = optional_name(_root, "createinet", 1, NULL); \ if (item) \ STRNCPY(_row->createinet, DATA_TRANSFER(item)->data); \ } while (0) @@ -569,21 +570,21 @@ static const tv_t date_begin = { DATE_BEGIN, 0L }; #define SIMPLEDATEDEFAULT(_row, _cd) do { \ _row->createdate.tv_sec = (_cd)->tv_sec; \ _row->createdate.tv_usec = (_cd)->tv_usec; \ - STRNCPY(_row->createby, (char *)"code"); \ + STRNCPY(_row->createby, by_default); \ STRNCPY(_row->createcode, (char *)__func__); \ - STRNCPY(_row->createinet, (char *)"127.0.0.1"); \ + STRNCPY(_row->createinet, inet_default); \ } while (0) // Override _row defaults if transfer fields are present -#define SIMPLEDATETRANSFER(_row) do { \ +#define SIMPLEDATETRANSFER(_root, _row) do { \ K_ITEM *item; \ - item = optional_name("createby", 1, NULL); \ + item = optional_name(_root, "createby", 1, NULL); \ if (item) \ STRNCPY(_row->createby, DATA_TRANSFER(item)->data); \ - item = optional_name("createcode", 1, NULL); \ + item = optional_name(_root, "createcode", 1, NULL); \ if (item) \ STRNCPY(_row->createcode, DATA_TRANSFER(item)->data); \ - item = optional_name("createinet", 1, NULL); \ + item = optional_name(_root, "createinet", 1, NULL); \ if (item) \ STRNCPY(_row->createinet, DATA_TRANSFER(item)->data); \ } while (0) @@ -626,14 +627,20 @@ static const tv_t date_begin = { DATE_BEGIN, 0L }; } \ } while (0) -// Different input data handling -static bool reloading = false; +// DB users,workers,auth load is complete +static bool db_auths_complete = false; // DB load is complete static bool db_load_complete = false; +// Different input data handling +static bool reloading = false; // Data load is complete static bool startup_complete = false; -// Tell the summarizer to die -static bool summarizer_die = false; +// Tell everyone to die +static bool everyone_die = false; + +static cklock_t fpm_lock; +static char *first_pool_message; +static sem_t socketer_sem; static const char *userpatt = "^[!-~]*$"; // no spaces static const char *mailpatt = "^[A-Za-z0-9_-][A-Za-z0-9_\\.-]*@[A-Za-z0-9][A-Za-z0-9\\.]*[A-Za-z0-9]$"; @@ -650,6 +657,55 @@ static const char *hashpatt = "^[A-Fa-f0-9]*$"; #define STR_SHAREERRORS "shareerror" #define STR_AGEWORKINFO "ageworkinfo" +static char *by_default = "code"; +static char *inet_default = "127.0.0.1"; + +enum cmd_values { + CMD_UNSET, + CMD_REPLY, // Means something was wrong - send back reply + CMD_SHUTDOWN, + CMD_PING, + CMD_SHARELOG, + CMD_AUTH, + CMD_ADDUSER, + CMD_CHKPASS, + CMD_POOLSTAT, + CMD_USERSTAT, + CMD_BLOCK, + CMD_NEWID, + CMD_PAYMENTS, + CMD_WORKERS, + CMD_ALLUSERS, + CMD_HOMEPAGE, + CMD_DSP, + CMD_STATS, + CMD_END +}; + +// WORKQUEUE +typedef struct workqueue { + char *buf; + int which_cmds; + enum cmd_values cmdnum; + char cmd[CMD_SIZ+1]; + char id[ID_SIZ+1]; + tv_t now; + char by[TXT_SML+1]; + char code[TXT_MED+1]; + char inet[TXT_MED+1]; + tv_t cd; + K_TREE *trf_root; + K_STORE *trf_store; +} WORKQUEUE; + +#define ALLOC_WORKQUEUE 1024 +#define LIMIT_WORKQUEUE 0 +#define DATA_WORKQUEUE(_item) ((WORKQUEUE *)(_item->data)) + +static K_LIST *workqueue_free; +static K_STORE *workqueue_store; +static sem_t workqueue_sem; + // TRANSFER #define NAME_SIZE 63 #define VALUE_SIZE 1023 @@ -663,9 +719,7 @@ typedef struct transfer { #define LIMIT_TRANSFER 0 #define DATA_TRANSFER(_item) ((TRANSFER *)(_item->data)) -static K_TREE *transfer_root; static K_LIST *transfer_free; -static K_STORE *transfer_store; // older version missing field defaults static TRANSFER auth_1 = { "poolinstance", "", auth_1.value }; @@ -1331,7 +1385,7 @@ static cmp_t cmp_transfer(K_ITEM *a, K_ITEM *b) DATA_TRANSFER(b)->name); } -static K_ITEM *find_transfer(char *name) +static K_ITEM *find_transfer(K_TREE *trf_root, char *name) { TRANSFER transfer; K_TREE_CTX ctx[1]; @@ -1339,17 +1393,17 @@ static K_ITEM *find_transfer(char *name) STRNCPY(transfer.name, name); look.data = (void *)(&transfer); - return find_in_ktree(transfer_root, &look, cmp_transfer, ctx); + return find_in_ktree(trf_root, &look, cmp_transfer, ctx); } -static K_ITEM *optional_name(char *name, int len, char *patt) +static K_ITEM *optional_name(K_TREE *trf_root, char *name, int len, char *patt) { K_ITEM *item; char *value; regex_t re; int ret; - item = find_transfer(name); + item = find_transfer(trf_root, name); if (!item) return NULL; @@ -1371,12 +1425,12 @@ static K_ITEM *optional_name(char *name, int len, char *patt) return item; } -#define require_name(_name, _len, _patt, _reply, _siz) \ - _require_name(_name, _len, _patt, _reply, _siz, \ - WHERE_FFL_HERE) +#define require_name(_root, _name, _len, _patt, _reply, _siz) \ + _require_name(_root, _name, _len, _patt, _reply, \ + _siz, WHERE_FFL_HERE) -static K_ITEM *_require_name(char *name, int len, char *patt, char *reply, - size_t siz, WHERE_FFL_ARGS) +static K_ITEM *_require_name(K_TREE *trf_root, char *name, int len, char *patt, + char *reply, size_t siz, WHERE_FFL_ARGS) { K_ITEM *item; char *value; @@ -1384,7 +1438,7 @@ static K_ITEM *_require_name(char *name, int len, char *patt, char *reply, size_t dlen; int ret; - item = find_transfer(name); + item = find_transfer(trf_root, name); if (!item) { LOGERR("%s(): failed, field '%s' missing from %s():%d", __func__, name, func, line); @@ -1838,13 +1892,16 @@ static K_ITEM *get_workerstatus(int64_t userid, char *workername) { WORKERSTATUS workerstatus; K_TREE_CTX ctx[1]; - K_ITEM look; + K_ITEM look, *find; workerstatus.userid = userid; STRNCPY(workerstatus.workername, workername); look.data = (void *)(&workerstatus); - return find_in_ktree(workerstatus_root, &look, cmp_workerstatus, ctx); + K_RLOCK(workerstatus_free); + find = find_in_ktree(workerstatus_root, &look, cmp_workerstatus, ctx); + K_RUNLOCK(workerstatus_free); + return find; } static K_ITEM *_find_create_workerstatus(int64_t userid, char *workername, bool create) @@ -1992,6 +2049,7 @@ static cmp_t cmp_userid(K_ITEM *a, K_ITEM *b) return c; } +// Must be R or W locked before call static K_ITEM *find_users(char *username) { USERS users; @@ -2006,6 +2064,7 @@ static K_ITEM *find_users(char *username) return find_in_ktree(users_root, &look, cmp_users, ctx); } +// Must be R or W locked before call static K_ITEM *find_userid(int64_t userid) { USERS users; @@ -2547,7 +2606,9 @@ static K_ITEM *new_worker_find_user(PGconn *conn, bool update, char *username, { K_ITEM *item; + K_RLOCK(users_free); item = find_users(username); + K_RUNLOCK(users_free); if (!item) return NULL; @@ -2882,13 +2943,15 @@ static int64_t workinfo_add(PGconn *conn, char *workinfoidstr, char *poolinstanc char *transactiontree, char *merklehash, char *prevhash, char *coinbase1, char *coinbase2, char *version, char *bits, char *ntime, char *reward, char *by, - char *code, char *inet, tv_t *cd, bool igndup) + char *code, char *inet, tv_t *cd, bool igndup, + K_TREE *trf_root) { ExecStatusType rescode; bool conned = false; K_TREE_CTX ctx[1]; PGresult *res; K_ITEM *item; + char cd_buf[DATE_BUFSIZ]; int n; int64_t workinfoid = -1; WORKINFO *row; @@ -2917,15 +2980,23 @@ static int64_t workinfo_add(PGconn *conn, char *workinfoidstr, char *poolinstanc TXT_TO_BIGINT("reward", reward, row->reward); HISTORYDATEINIT(row, cd, by, code, inet); - HISTORYDATETRANSFER(row); + HISTORYDATETRANSFER(trf_root, row); - if (igndup && find_in_ktree(workinfo_root, item, cmp_workinfo, ctx)) { + K_WLOCK(workinfo_free); + if (find_in_ktree(workinfo_root, item, cmp_workinfo, ctx)) { workinfoid = row->workinfoid; - K_WLOCK(workinfo_free); k_add_head(workinfo_free, item); K_WUNLOCK(workinfo_free); + + if (!igndup) { + tv_to_buf(cd, cd_buf, sizeof(cd_buf)); + LOGERR("%s(): Duplicate workinfo ignored %s/%s/%s", + __func__, workinfoidstr, poolinstance, cd_buf); + } + return workinfoid; } + K_WUNLOCK(workinfo_free); par = 0; params[par++] = bigint_to_buf(row->workinfoid, NULL, 0); @@ -3314,7 +3385,7 @@ static K_ITEM *find_sharesummary(int64_t userid, char *workername, int64_t worki static bool shares_add(PGconn *conn, char *workinfoid, char *username, char *workername, char *clientid, char *enonce1, char *nonce2, char *nonce, char *diff, char *sdiff, char *secondaryuserid, char *by, - char *code, char *inet, tv_t *cd) + char *code, char *inet, tv_t *cd, K_TREE *trf_root) { K_ITEM *s_item, *u_item, *wi_item, *w_item, *ss_item; SHARES *shares; @@ -3329,7 +3400,9 @@ static bool shares_add(PGconn *conn, char *workinfoid, char *username, char *wor shares = DATA_SHARES(s_item); // TODO: allow BTC address later? + K_RLOCK(users_free); u_item = find_users(username); + K_RUNLOCK(users_free); if (!u_item) goto unitem; @@ -3346,7 +3419,7 @@ static bool shares_add(PGconn *conn, char *workinfoid, char *username, char *wor STRNCPY(shares->secondaryuserid, secondaryuserid); HISTORYDATEINIT(shares, cd, by, code, inet); - HISTORYDATETRANSFER(shares); + HISTORYDATETRANSFER(trf_root, shares); wi_item = find_workinfo(shares->workinfoid); if (!wi_item) @@ -3425,7 +3498,7 @@ static cmp_t cmp_shareerrors(K_ITEM *a, K_ITEM *b) static bool shareerrors_add(PGconn *conn, char *workinfoid, char *username, char *workername, char *clientid, char *errn, char *error, char *secondaryuserid, char *by, - char *code, char *inet, tv_t *cd) + char *code, char *inet, tv_t *cd, K_TREE *trf_root) { K_ITEM *s_item, *u_item, *wi_item, *w_item, *ss_item; SHAREERRORS *shareerrors; @@ -3440,7 +3513,9 @@ static bool shareerrors_add(PGconn *conn, char *workinfoid, char *username, shareerrors = DATA_SHAREERRORS(s_item); // TODO: allow BTC address later? + K_RLOCK(users_free); u_item = find_users(username); + K_RUNLOCK(users_free); if (!u_item) goto unitem; @@ -3454,7 +3529,7 @@ static bool shareerrors_add(PGconn *conn, char *workinfoid, char *username, STRNCPY(shareerrors->secondaryuserid, secondaryuserid); HISTORYDATEINIT(shareerrors, cd, by, code, inet); - HISTORYDATETRANSFER(shareerrors); + HISTORYDATETRANSFER(trf_root, shareerrors); wi_item = find_workinfo(shareerrors->workinfoid); if (!wi_item) @@ -4081,7 +4156,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, char *workername, char *clientid, char *enonce1, char *nonce2, char *nonce, char *reward, char *by, char *code, char *inet, tv_t *cd, - bool igndup, char *id) + bool igndup, char *id, K_TREE *trf_root) { ExecStatusType rescode; bool conned = false; @@ -4111,7 +4186,9 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, switch (confirmed[0]) { case BLOCKS_NEW: + K_RLOCK(users_free); u_item = find_users(username); + K_RUNLOCK(users_free); if (!u_item) row->userid = KANO; else @@ -4125,7 +4202,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, STRNCPY(row->nonce, nonce); TXT_TO_BIGINT("reward", reward, row->reward); - HISTORYDATETRANSFER(row); + HISTORYDATETRANSFER(trf_root, row); if (igndup && find_in_ktree(blocks_root, item, cmp_blocks, ctx)) { K_WLOCK(blocks_free); @@ -4418,13 +4495,14 @@ static cmp_t cmp_auths(K_ITEM *a, K_ITEM *b) static char *auths_add(PGconn *conn, char *poolinstance, char *username, char *workername, char *clientid, char *enonce1, char *useragent, char *by, char *code, char *inet, - tv_t *cd, bool igndup) + tv_t *cd, bool igndup, K_TREE *trf_root) { ExecStatusType rescode; bool conned = false; PGresult *res; K_TREE_CTX ctx[1]; K_ITEM *a_item, *u_item; + char cd_buf[DATE_BUFSIZ]; int n; AUTHS *row; char *ins; @@ -4440,7 +4518,9 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username, row = DATA_AUTHS(a_item); + K_RLOCK(users_free); u_item = find_users(username); + K_RUNLOCK(users_free); if (!u_item) goto unitem; @@ -4456,14 +4536,22 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username, STRNCPY(row->useragent, useragent); HISTORYDATEINIT(row, cd, by, code, inet); - HISTORYDATETRANSFER(row); + HISTORYDATETRANSFER(trf_root, row); - if (igndup && find_in_ktree(auths_root, a_item, cmp_auths, ctx)) { - K_WLOCK(auths_free); + K_WLOCK(auths_free); + if (find_in_ktree(auths_root, a_item, cmp_auths, ctx)) { k_add_head(auths_free, a_item); K_WUNLOCK(auths_free); + + if (!igndup) { + tv_to_buf(cd, cd_buf, sizeof(cd_buf)); + LOGERR("%s(): Duplicate auths ignored %s/%s/%s", + __func__, poolinstance, workername, cd_buf); + } + return DATA_USERS(u_item)->secondaryuserid; } + K_WUNLOCK(auths_free); // Update even if DB fails workerstatus_update(row, NULL, NULL, NULL); @@ -4656,7 +4744,7 @@ static bool poolstats_add(PGconn *conn, bool store, char *poolinstance, char *hashrate, char *hashrate5m, char *hashrate1hr, char *hashrate24hr, char *by, char *code, char *inet, tv_t *cd, - bool igndup) + bool igndup, K_TREE *trf_root) { ExecStatusType rescode; bool conned = false; @@ -4690,7 +4778,7 @@ static bool poolstats_add(PGconn *conn, bool store, char *poolinstance, TXT_TO_DOUBLE("hashrate24hr", hashrate24hr, row->hashrate24hr); SIMPLEDATEINIT(row, cd, by, code, inet); - SIMPLEDATETRANSFER(row); + SIMPLEDATETRANSFER(trf_root, row); if (igndup && find_in_ktree(poolstats_root, p_item, cmp_poolstats, ctx)) { K_WLOCK(poolstats_free); @@ -5036,7 +5124,8 @@ unparam: static bool userstats_add(char *poolinstance, char *elapsed, char *username, char *workername, char *hashrate, char *hashrate5m, char *hashrate1hr, char *hashrate24hr, bool idle, - bool eos, char *by, char *code, char *inet, tv_t *cd) + bool eos, char *by, char *code, char *inet, tv_t *cd, + K_TREE *trf_root) { K_ITEM *us_item, *u_item, *us_match, *us_next, look; tv_t eosdate; @@ -5053,7 +5142,9 @@ static bool userstats_add(char *poolinstance, char *elapsed, char *username, STRNCPY(row->poolinstance, poolinstance); TXT_TO_BIGINT("elapsed", elapsed, row->elapsed); + K_RLOCK(users_free); u_item = find_users(username); + K_RUNLOCK(users_free); if (!u_item) return false; row->userid = DATA_USERS(u_item)->userid; @@ -5067,7 +5158,7 @@ static bool userstats_add(char *poolinstance, char *elapsed, char *username, row->summarylevel[1] = '\0'; row->summarycount = 1; SIMPLEDATEINIT(row, cd, by, code, inet); - SIMPLEDATETRANSFER(row); + SIMPLEDATETRANSFER(trf_root, row); copy_tv(&(row->statsdate), &(row->createdate)); if (eos) { @@ -5419,6 +5510,9 @@ static bool check_db_version(PGconn *conn) return true; } +/* Load tables required to support auths,adduser,chkpass and newid + * N.B. idcontrol is DB internal so is always ready + */ static bool getdata1() { PGconn *conn = dbconnect(); @@ -5465,9 +5559,9 @@ sukamudai: return ok; } -static void reload_from(tv_t *start); +static bool reload_from(tv_t *start); -static void reload() +static bool reload() { char buf[DATE_BUFSIZ+1]; char *filename; @@ -5536,7 +5630,7 @@ static void reload() } free(filename); } - reload_from(&start); + return reload_from(&start); } /* TODO: @@ -5635,10 +5729,16 @@ static bool setup_data() K_ITEM look, *found; WORKINFO wi; + cklock_init(&fpm_lock); + cksem_init(&workqueue_sem); + cksem_init(&socketer_sem); + + workqueue_free = k_new_list("WorkQueue", sizeof(WORKQUEUE), + ALLOC_WORKQUEUE, LIMIT_WORKQUEUE, true); + workqueue_store = k_new_store(workqueue_free); + transfer_free = k_new_list("Transfer", sizeof(TRANSFER), ALLOC_TRANSFER, LIMIT_TRANSFER, true); - transfer_store = k_new_store(transfer_free); - transfer_root = new_ktree(); transfer_free->dsp_func = dsp_transfer; users_free = k_new_list("Users", sizeof(USERS), @@ -5717,12 +5817,16 @@ static bool setup_data() if (!getdata1()) return false; + db_auths_complete = true; + cksem_post(&socketer_sem); + if (!getdata2()) return false; db_load_complete = true; - reload(); + if (!reload()) + return false; workerstatus_ready(); @@ -5746,7 +5850,8 @@ static bool setup_data() } static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by, - char *code, char *inet, __maybe_unused tv_t *notcd) + char *code, char *inet, __maybe_unused tv_t *notcd, + K_TREE *trf_root) { char reply[1024] = ""; size_t siz = sizeof(reply); @@ -5756,15 +5861,15 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_username = require_name("username", 3, (char *)userpatt, reply, siz); + i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); if (!i_username) return strdup(reply); - i_emailaddress = require_name("emailaddress", 7, (char *)mailpatt, reply, siz); + i_emailaddress = require_name(trf_root, "emailaddress", 7, (char *)mailpatt, reply, siz); if (!i_emailaddress) return strdup(reply); - i_passwordhash = require_name("passwordhash", 64, (char *)hashpatt, reply, siz); + i_passwordhash = require_name(trf_root, "passwordhash", 64, (char *)hashpatt, reply, siz); if (!i_passwordhash) return strdup(reply); @@ -5785,7 +5890,7 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by, static char *cmd_chkpass(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) + __maybe_unused tv_t *notcd, K_TREE *trf_root) { K_ITEM *i_username, *i_passwordhash, *u_item; char reply[1024] = ""; @@ -5794,15 +5899,17 @@ static char *cmd_chkpass(__maybe_unused PGconn *conn, char *cmd, char *id, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_username = require_name("username", 3, (char *)userpatt, reply, siz); + i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); if (!i_username) return strdup(reply); - i_passwordhash = require_name("passwordhash", 64, (char *)hashpatt, reply, siz); + i_passwordhash = require_name(trf_root, "passwordhash", 64, (char *)hashpatt, reply, siz); if (!i_passwordhash) return strdup(reply); + K_RLOCK(users_free); u_item = find_users(DATA_TRANSFER(i_username)->data); + K_RUNLOCK(users_free); if (!u_item) ok = false; @@ -5822,7 +5929,8 @@ static char *cmd_chkpass(__maybe_unused PGconn *conn, char *cmd, char *id, } static char *cmd_poolstats_do(PGconn *conn, char *cmd, char *id, char *by, - char *code, char *inet, tv_t *cd, bool igndup) + char *code, char *inet, tv_t *cd, bool igndup, + K_TREE *trf_root) { char reply[1024] = ""; size_t siz = sizeof(reply); @@ -5839,35 +5947,35 @@ static char *cmd_poolstats_do(PGconn *conn, char *cmd, char *id, char *by, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_poolinstance = require_name("poolinstance", 1, NULL, reply, siz); + i_poolinstance = require_name(trf_root, "poolinstance", 1, NULL, reply, siz); if (!i_poolinstance) return strdup(reply); - i_elapsed = optional_name("elapsed", 1, NULL); + i_elapsed = optional_name(trf_root, "elapsed", 1, NULL); if (!i_elapsed) i_elapsed = &poolstats_elapsed; - i_users = require_name("users", 1, NULL, reply, siz); + i_users = require_name(trf_root, "users", 1, NULL, reply, siz); if (!i_users) return strdup(reply); - i_workers = require_name("workers", 1, NULL, reply, siz); + i_workers = require_name(trf_root, "workers", 1, NULL, reply, siz); if (!i_workers) return strdup(reply); - i_hashrate = require_name("hashrate", 1, NULL, reply, siz); + i_hashrate = require_name(trf_root, "hashrate", 1, NULL, reply, siz); if (!i_hashrate) return strdup(reply); - i_hashrate5m = require_name("hashrate5m", 1, NULL, reply, siz); + i_hashrate5m = require_name(trf_root, "hashrate5m", 1, NULL, reply, siz); if (!i_hashrate5m) return strdup(reply); - i_hashrate1hr = require_name("hashrate1hr", 1, NULL, reply, siz); + i_hashrate1hr = require_name(trf_root, "hashrate1hr", 1, NULL, reply, siz); if (!i_hashrate1hr) return strdup(reply); - i_hashrate24hr = require_name("hashrate24hr", 1, NULL, reply, siz); + i_hashrate24hr = require_name(trf_root, "hashrate24hr", 1, NULL, reply, siz); if (!i_hashrate24hr) return strdup(reply); @@ -5902,7 +6010,7 @@ static char *cmd_poolstats_do(PGconn *conn, char *cmd, char *id, char *by, DATA_TRANSFER(i_hashrate5m)->data, DATA_TRANSFER(i_hashrate1hr)->data, DATA_TRANSFER(i_hashrate24hr)->data, - by, code, inet, cd, igndup); + by, code, inet, cd, igndup, trf_root); if (!ok) { LOGERR("%s.failed.DBE", id); @@ -5915,7 +6023,8 @@ static char *cmd_poolstats_do(PGconn *conn, char *cmd, char *id, char *by, static char *cmd_poolstats(PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *notnow, char *by, - char *code, char *inet, tv_t *cd) + char *code, char *inet, tv_t *cd, + K_TREE *trf_root) { bool igndup = false; @@ -5926,12 +6035,12 @@ static char *cmd_poolstats(PGconn *conn, char *cmd, char *id, return NULL; } - return cmd_poolstats_do(conn, cmd, id, by, code, inet, cd, igndup); + return cmd_poolstats_do(conn, cmd, id, by, code, inet, cd, igndup, trf_root); } static char *cmd_userstats(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *notnow, char *by, char *code, - char *inet, tv_t *cd) + char *inet, tv_t *cd, K_TREE *trf_root) { char reply[1024] = ""; size_t siz = sizeof(reply); @@ -5945,45 +6054,45 @@ static char *cmd_userstats(__maybe_unused PGconn *conn, char *cmd, char *id, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_poolinstance = require_name("poolinstance", 1, NULL, reply, siz); + i_poolinstance = require_name(trf_root, "poolinstance", 1, NULL, reply, siz); if (!i_poolinstance) return strdup(reply); - i_elapsed = optional_name("elapsed", 1, NULL); + i_elapsed = optional_name(trf_root, "elapsed", 1, NULL); if (!i_elapsed) i_elapsed = &userstats_elapsed; - i_username = require_name("username", 1, NULL, reply, siz); + i_username = require_name(trf_root, "username", 1, NULL, reply, siz); if (!i_username) return strdup(reply); - i_workername = optional_name("workername", 1, NULL); + i_workername = optional_name(trf_root, "workername", 1, NULL); if (!i_workername) i_workername = &userstats_workername; - i_hashrate = require_name("hashrate", 1, NULL, reply, siz); + i_hashrate = require_name(trf_root, "hashrate", 1, NULL, reply, siz); if (!i_hashrate) return strdup(reply); - i_hashrate5m = require_name("hashrate5m", 1, NULL, reply, siz); + i_hashrate5m = require_name(trf_root, "hashrate5m", 1, NULL, reply, siz); if (!i_hashrate5m) return strdup(reply); - i_hashrate1hr = require_name("hashrate1hr", 1, NULL, reply, siz); + i_hashrate1hr = require_name(trf_root, "hashrate1hr", 1, NULL, reply, siz); if (!i_hashrate1hr) return strdup(reply); - i_hashrate24hr = require_name("hashrate24hr", 1, NULL, reply, siz); + i_hashrate24hr = require_name(trf_root, "hashrate24hr", 1, NULL, reply, siz); if (!i_hashrate24hr) return strdup(reply); - i_idle = optional_name("idle", 1, NULL); + i_idle = optional_name(trf_root, "idle", 1, NULL); if (!i_idle) i_idle = &userstats_idle; idle = (strcasecmp(DATA_TRANSFER(i_idle)->data, TRUE_STR) == 0); - i_eos = optional_name("eos", 1, NULL); + i_eos = optional_name(trf_root, "eos", 1, NULL); if (!i_eos) i_eos = &userstats_eos; @@ -5997,7 +6106,7 @@ static char *cmd_userstats(__maybe_unused PGconn *conn, char *cmd, char *id, DATA_TRANSFER(i_hashrate5m)->data, DATA_TRANSFER(i_hashrate1hr)->data, DATA_TRANSFER(i_hashrate24hr)->data, - idle, eos, by, code, inet, cd); + idle, eos, by, code, inet, cd, trf_root); if (!ok) { LOGERR("%s.failed.DATA", id); @@ -6009,7 +6118,8 @@ static char *cmd_userstats(__maybe_unused PGconn *conn, char *cmd, char *id, } static char *cmd_newid(PGconn *conn, char *cmd, char *id, tv_t *now, char *by, - char *code, char *inet, __maybe_unused tv_t *cd) + char *code, char *inet, __maybe_unused tv_t *cd, + K_TREE *trf_root) { char reply[1024] = ""; size_t siz = sizeof(reply); @@ -6026,11 +6136,11 @@ static char *cmd_newid(PGconn *conn, char *cmd, char *id, tv_t *now, char *by, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_idname = require_name("idname", 3, (char *)idpatt, reply, siz); + i_idname = require_name(trf_root, "idname", 3, (char *)idpatt, reply, siz); if (!i_idname) return strdup(reply); - i_idvalue = require_name("idvalue", 1, (char *)intpatt, reply, siz); + i_idvalue = require_name(trf_root, "idvalue", 1, (char *)intpatt, reply, siz); if (!i_idvalue) return strdup(reply); @@ -6090,7 +6200,8 @@ foil: static char *cmd_payments(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) + __maybe_unused tv_t *notcd, + __maybe_unused K_TREE *trf_root) { K_ITEM *i_username, look, *u_item, *p_item; K_TREE_CTX ctx[1]; @@ -6104,11 +6215,13 @@ static char *cmd_payments(__maybe_unused PGconn *conn, char *cmd, char *id, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_username = require_name("username", 3, (char *)userpatt, reply, siz); + i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); if (!i_username) return strdup(reply); + K_RLOCK(users_free); u_item = find_users(DATA_TRANSFER(i_username)->data); + K_RUNLOCK(users_free); if (!u_item) return strdup("bad"); @@ -6146,7 +6259,7 @@ static char *cmd_payments(__maybe_unused PGconn *conn, char *cmd, char *id, static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) + __maybe_unused tv_t *notcd, K_TREE *trf_root) { K_ITEM *i_username, *i_stats, wlook, *u_item, *w_item, uslook, *us_item, *ws_item; K_TREE_CTX w_ctx[1], us_ctx[1]; @@ -6162,15 +6275,17 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_username = require_name("username", 3, (char *)userpatt, reply, siz); + i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); if (!i_username) return strdup(reply); + K_RLOCK(users_free); u_item = find_users(DATA_TRANSFER(i_username)->data); + K_RUNLOCK(users_free); if (!u_item) return strdup("bad"); - i_stats = optional_name("stats", 1, NULL); + i_stats = optional_name(trf_root, "stats", 1, NULL); if (!i_stats) stats = false; else @@ -6284,7 +6399,8 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id, static char *cmd_allusers(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) + __maybe_unused tv_t *notcd, + __maybe_unused K_TREE *trf_root) { K_TREE *userstats_workername_root = new_ktree(); K_ITEM *us_item, *usw_item, *tmp_item, *u_item; @@ -6325,7 +6441,9 @@ static char *cmd_allusers(__maybe_unused PGconn *conn, char *cmd, char *id, while (usw_item) { if (DATA_USERSTATS(usw_item)->userid != userid) { if (userid != -1) { + K_RLOCK(users_free); u_item = find_userid(userid); + K_RUNLOCK(users_free); if (!u_item) { LOGERR("%s() userid %"PRId64" ignored - userstats but not users", __func__, userid); @@ -6356,7 +6474,9 @@ static char *cmd_allusers(__maybe_unused PGconn *conn, char *cmd, char *id, k_add_head(userstats_free, tmp_item); } if (userid != -1) { + K_RLOCK(users_free); u_item = find_userid(userid); + K_RUNLOCK(users_free); if (!u_item) { LOGERR("%s() userid %"PRId64" ignored - userstats but not users", __func__, userid); @@ -6389,7 +6509,8 @@ static char *cmd_allusers(__maybe_unused PGconn *conn, char *cmd, char *id, static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *notnow, char *by, - char *code, char *inet, tv_t *cd) + char *code, char *inet, tv_t *cd, + K_TREE *trf_root) { char reply[1024] = ""; size_t siz = sizeof(reply); @@ -6412,47 +6533,47 @@ static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, return NULL; } - i_workinfoid = require_name("workinfoid", 1, NULL, reply, siz); + i_workinfoid = require_name(trf_root, "workinfoid", 1, NULL, reply, siz); if (!i_workinfoid) return strdup(reply); - i_poolinstance = require_name("poolinstance", 1, NULL, reply, siz); + i_poolinstance = require_name(trf_root, "poolinstance", 1, NULL, reply, siz); if (!i_poolinstance) return strdup(reply); - i_transactiontree = require_name("transactiontree", 0, NULL, reply, siz); + i_transactiontree = require_name(trf_root, "transactiontree", 0, NULL, reply, siz); if (!i_transactiontree) return strdup(reply); - i_merklehash = require_name("merklehash", 0, NULL, reply, siz); + i_merklehash = require_name(trf_root, "merklehash", 0, NULL, reply, siz); if (!i_merklehash) return strdup(reply); - i_prevhash = require_name("prevhash", 1, NULL, reply, siz); + i_prevhash = require_name(trf_root, "prevhash", 1, NULL, reply, siz); if (!i_prevhash) return strdup(reply); - i_coinbase1 = require_name("coinbase1", 1, NULL, reply, siz); + i_coinbase1 = require_name(trf_root, "coinbase1", 1, NULL, reply, siz); if (!i_coinbase1) return strdup(reply); - i_coinbase2 = require_name("coinbase2", 1, NULL, reply, siz); + i_coinbase2 = require_name(trf_root, "coinbase2", 1, NULL, reply, siz); if (!i_coinbase2) return strdup(reply); - i_version = require_name("version", 1, NULL, reply, siz); + i_version = require_name(trf_root, "version", 1, NULL, reply, siz); if (!i_version) return strdup(reply); - i_bits = require_name("bits", 1, NULL, reply, siz); + i_bits = require_name(trf_root, "bits", 1, NULL, reply, siz); if (!i_bits) return strdup(reply); - i_ntime = require_name("ntime", 1, NULL, reply, siz); + i_ntime = require_name(trf_root, "ntime", 1, NULL, reply, siz); if (!i_ntime) return strdup(reply); - i_reward = require_name("reward", 1, NULL, reply, siz); + i_reward = require_name(trf_root, "reward", 1, NULL, reply, siz); if (!i_reward) return strdup(reply); @@ -6467,7 +6588,7 @@ static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, DATA_TRANSFER(i_bits)->data, DATA_TRANSFER(i_ntime)->data, DATA_TRANSFER(i_reward)->data, - by, code, inet, cd, igndup); + by, code, inet, cd, igndup, trf_root); if (workinfoid == -1) { LOGERR("%s.failed.DBE", id); @@ -6487,43 +6608,43 @@ static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, return NULL; } - i_workinfoid = require_name("workinfoid", 1, NULL, reply, siz); + i_workinfoid = require_name(trf_root, "workinfoid", 1, NULL, reply, siz); if (!i_workinfoid) return strdup(reply); - i_username = require_name("username", 1, NULL, reply, siz); + i_username = require_name(trf_root, "username", 1, NULL, reply, siz); if (!i_username) return strdup(reply); - i_workername = require_name("workername", 1, NULL, reply, siz); + i_workername = require_name(trf_root, "workername", 1, NULL, reply, siz); if (!i_workername) return strdup(reply); - i_clientid = require_name("clientid", 1, NULL, reply, siz); + i_clientid = require_name(trf_root, "clientid", 1, NULL, reply, siz); if (!i_clientid) return strdup(reply); - i_enonce1 = require_name("enonce1", 1, NULL, reply, siz); + i_enonce1 = require_name(trf_root, "enonce1", 1, NULL, reply, siz); if (!i_enonce1) return strdup(reply); - i_nonce2 = require_name("nonce2", 1, NULL, reply, siz); + i_nonce2 = require_name(trf_root, "nonce2", 1, NULL, reply, siz); if (!i_nonce2) return strdup(reply); - i_nonce = require_name("nonce", 1, NULL, reply, siz); + i_nonce = require_name(trf_root, "nonce", 1, NULL, reply, siz); if (!i_nonce) return strdup(reply); - i_diff = require_name("diff", 1, NULL, reply, siz); + i_diff = require_name(trf_root, "diff", 1, NULL, reply, siz); if (!i_diff) return strdup(reply); - i_sdiff = require_name("sdiff", 1, NULL, reply, siz); + i_sdiff = require_name(trf_root, "sdiff", 1, NULL, reply, siz); if (!i_sdiff) return strdup(reply); - i_secondaryuserid = require_name("secondaryuserid", 1, NULL, reply, siz); + i_secondaryuserid = require_name(trf_root, "secondaryuserid", 1, NULL, reply, siz); if (!i_secondaryuserid) return strdup(reply); @@ -6537,7 +6658,7 @@ static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, DATA_TRANSFER(i_diff)->data, DATA_TRANSFER(i_sdiff)->data, DATA_TRANSFER(i_secondaryuserid)->data, - by, code, inet, cd); + by, code, inet, cd, trf_root); if (!ok) { LOGERR("%s.failed.DATA", id); @@ -6557,31 +6678,31 @@ static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, return NULL; } - i_workinfoid = require_name("workinfoid", 1, NULL, reply, siz); + i_workinfoid = require_name(trf_root, "workinfoid", 1, NULL, reply, siz); if (!i_workinfoid) return strdup(reply); - i_username = require_name("username", 1, NULL, reply, siz); + i_username = require_name(trf_root, "username", 1, NULL, reply, siz); if (!i_username) return strdup(reply); - i_workername = require_name("workername", 1, NULL, reply, siz); + i_workername = require_name(trf_root, "workername", 1, NULL, reply, siz); if (!i_workername) return strdup(reply); - i_clientid = require_name("clientid", 1, NULL, reply, siz); + i_clientid = require_name(trf_root, "clientid", 1, NULL, reply, siz); if (!i_clientid) return strdup(reply); - i_errn = require_name("errn", 1, NULL, reply, siz); + i_errn = require_name(trf_root, "errn", 1, NULL, reply, siz); if (!i_errn) return strdup(reply); - i_error = require_name("error", 1, NULL, reply, siz); + i_error = require_name(trf_root, "error", 1, NULL, reply, siz); if (!i_error) return strdup(reply); - i_secondaryuserid = require_name("secondaryuserid", 1, NULL, reply, siz); + i_secondaryuserid = require_name(trf_root, "secondaryuserid", 1, NULL, reply, siz); if (!i_secondaryuserid) return strdup(reply); @@ -6592,7 +6713,7 @@ static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, DATA_TRANSFER(i_errn)->data, DATA_TRANSFER(i_error)->data, DATA_TRANSFER(i_secondaryuserid)->data, - by, code, inet, cd); + by, code, inet, cd, trf_root); if (!ok) { LOGERR("%s.failed.DATA", id); return strdup("failed.DATA"); @@ -6609,11 +6730,11 @@ static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, return NULL; } - i_workinfoid = require_name("workinfoid", 1, NULL, reply, siz); + i_workinfoid = require_name(trf_root, "workinfoid", 1, NULL, reply, siz); if (!i_workinfoid) return strdup(reply); - i_poolinstance = require_name("poolinstance", 1, NULL, reply, siz); + i_poolinstance = require_name(trf_root, "poolinstance", 1, NULL, reply, siz); if (!i_poolinstance) return strdup(reply); @@ -6640,7 +6761,8 @@ static char *cmd_sharelog(PGconn *conn, char *cmd, char *id, // TODO: the confirm update: identify block changes from workinfo height? static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by, - char *code, char *inet, tv_t *cd, bool igndup) + char *code, char *inet, tv_t *cd, bool igndup, + K_TREE *trf_root) { char reply[1024] = ""; size_t siz = sizeof(reply); @@ -6651,50 +6773,50 @@ static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_height = require_name("height", 1, NULL, reply, siz); + i_height = require_name(trf_root, "height", 1, NULL, reply, siz); if (!i_height) return strdup(reply); - i_blockhash = require_name("blockhash", 1, NULL, reply, siz); + i_blockhash = require_name(trf_root, "blockhash", 1, NULL, reply, siz); if (!i_blockhash) return strdup(reply); - i_confirmed = require_name("confirmed", 1, NULL, reply, siz); + i_confirmed = require_name(trf_root, "confirmed", 1, NULL, reply, siz); if (!i_confirmed) return strdup(reply); DATA_TRANSFER(i_confirmed)->data[0] = tolower(DATA_TRANSFER(i_confirmed)->data[0]); switch(DATA_TRANSFER(i_confirmed)->data[0]) { case BLOCKS_NEW: - i_workinfoid = require_name("workinfoid", 1, NULL, reply, siz); + i_workinfoid = require_name(trf_root, "workinfoid", 1, NULL, reply, siz); if (!i_workinfoid) return strdup(reply); - i_username = require_name("username", 1, NULL, reply, siz); + i_username = require_name(trf_root, "username", 1, NULL, reply, siz); if (!i_username) return strdup(reply); - i_workername = require_name("workername", 1, NULL, reply, siz); + i_workername = require_name(trf_root, "workername", 1, NULL, reply, siz); if (!i_workername) return strdup(reply); - i_clientid = require_name("clientid", 1, NULL, reply, siz); + i_clientid = require_name(trf_root, "clientid", 1, NULL, reply, siz); if (!i_clientid) return strdup(reply); - i_enonce1 = require_name("enonce1", 1, NULL, reply, siz); + i_enonce1 = require_name(trf_root, "enonce1", 1, NULL, reply, siz); if (!i_enonce1) return strdup(reply); - i_nonce2 = require_name("nonce2", 1, NULL, reply, siz); + i_nonce2 = require_name(trf_root, "nonce2", 1, NULL, reply, siz); if (!i_nonce2) return strdup(reply); - i_nonce = require_name("nonce", 1, NULL, reply, siz); + i_nonce = require_name(trf_root, "nonce", 1, NULL, reply, siz); if (!i_nonce) return strdup(reply); - i_reward = require_name("reward", 1, NULL, reply, siz); + i_reward = require_name(trf_root, "reward", 1, NULL, reply, siz); if (!i_reward) return strdup(reply); @@ -6710,7 +6832,8 @@ static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by, DATA_TRANSFER(i_nonce2)->data, DATA_TRANSFER(i_nonce)->data, DATA_TRANSFER(i_reward)->data, - by, code, inet, cd, igndup, id); + by, code, inet, cd, igndup, id, + trf_root); break; case BLOCKS_CONFIRM: msg = "confirmed"; @@ -6719,7 +6842,8 @@ static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by, DATA_TRANSFER(i_confirmed)->data, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, - by, code, inet, cd, igndup, id); + by, code, inet, cd, igndup, id, + trf_root); break; default: LOGERR("%s(): %s.failed.invalid confirm='%s'", @@ -6739,7 +6863,8 @@ static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by, static char *cmd_blocks(PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *notnow, char *by, - char *code, char *inet, tv_t *cd) + char *code, char *inet, tv_t *cd, + K_TREE *trf_root) { bool igndup = false; @@ -6750,11 +6875,12 @@ static char *cmd_blocks(PGconn *conn, char *cmd, char *id, return NULL; } - return cmd_blocks_do(conn, cmd, id, by, code, inet, cd, igndup); + return cmd_blocks_do(conn, cmd, id, by, code, inet, cd, igndup, trf_root); } static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by, - char *code, char *inet, tv_t *cd, bool igndup) + char *code, char *inet, tv_t *cd, bool igndup, + K_TREE *trf_root) { char reply[1024] = ""; size_t siz = sizeof(reply); @@ -6764,27 +6890,27 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_poolinstance = optional_name("poolinstance", 1, NULL); + i_poolinstance = optional_name(trf_root, "poolinstance", 1, NULL); if (!i_poolinstance) i_poolinstance = &auth_poolinstance; - i_username = require_name("username", 1, NULL, reply, siz); + i_username = require_name(trf_root, "username", 1, NULL, reply, siz); if (!i_username) return strdup(reply); - i_workername = require_name("workername", 1, NULL, reply, siz); + i_workername = require_name(trf_root, "workername", 1, NULL, reply, siz); if (!i_workername) return strdup(reply); - i_clientid = require_name("clientid", 1, NULL, reply, siz); + i_clientid = require_name(trf_root, "clientid", 1, NULL, reply, siz); if (!i_clientid) return strdup(reply); - i_enonce1 = require_name("enonce1", 1, NULL, reply, siz); + i_enonce1 = require_name(trf_root, "enonce1", 1, NULL, reply, siz); if (!i_enonce1) return strdup(reply); - i_useragent = require_name("useragent", 0, NULL, reply, siz); + i_useragent = require_name(trf_root, "useragent", 0, NULL, reply, siz); if (!i_useragent) return strdup(reply); @@ -6794,7 +6920,7 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by, DATA_TRANSFER(i_clientid)->data, DATA_TRANSFER(i_enonce1)->data, DATA_TRANSFER(i_useragent)->data, - by, code, inet, cd, igndup); + by, code, inet, cd, igndup, trf_root); if (!secuserid) { LOGDEBUG("%s.failed.DBE", id); @@ -6808,7 +6934,8 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by, static char *cmd_auth(PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *now, char *by, - char *code, char *inet, tv_t *cd) + char *code, char *inet, tv_t *cd, + K_TREE *trf_root) { bool igndup = false; @@ -6819,13 +6946,13 @@ static char *cmd_auth(PGconn *conn, char *cmd, char *id, return NULL; } - return cmd_auth_do(conn, cmd, id, by, code, inet, cd, igndup); + return cmd_auth_do(conn, cmd, id, by, code, inet, cd, igndup, trf_root); } static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) + __maybe_unused tv_t *notcd, K_TREE *trf_root) { K_ITEM *i_username, *u_item, *b_item, *p_item, *us_item, look; double u_hashrate5m, u_hashrate1hr; @@ -6838,7 +6965,7 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id, LOGDEBUG("%s(): cmd '%s'", __func__, cmd); - i_username = optional_name("username", 1, NULL); + i_username = optional_name(trf_root, "username", 1, NULL); APPEND_REALLOC_INIT(buf, off, len); APPEND_REALLOC(buf, off, len, "ok."); @@ -6895,8 +7022,11 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id, } u_item = NULL; - if (i_username) + if (i_username) { + K_RLOCK(users_free); u_item = find_users(DATA_TRANSFER(i_username)->data); + K_RUNLOCK(users_free); + } has_uhr = false; if (p_item && u_item) { @@ -6962,7 +7092,8 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id, static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, - __maybe_unused char *inet, __maybe_unused tv_t *notcd) + __maybe_unused char *inet, __maybe_unused tv_t *notcd, + __maybe_unused K_TREE *trf_root) { __maybe_unused K_ITEM *i_file; __maybe_unused char reply[1024] = ""; @@ -6974,11 +7105,11 @@ static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd, LOGDEBUG("%s.disabled.dsp", id); return strdup("disabled.dsp"); /* - i_file = require_name("file", 1, NULL, reply, siz); + i_file = require_name(trf_root, "file", 1, NULL, reply, siz); if (!i_file) return strdup(reply); - dsp_ktree(transfer_free, transfer_root, DATA_TRANSFER(i_file)->data, NULL); + dsp_ktree(transfer_free, trf_root, DATA_TRANSFER(i_file)->data, NULL); dsp_ktree(sharesummary_free, sharesummary_root, DATA_TRANSFER(i_file)->data, NULL); @@ -6992,7 +7123,7 @@ static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd, static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, __maybe_unused char *inet, - __maybe_unused tv_t *notcd) + __maybe_unused tv_t *notcd, __maybe_unused K_TREE *trf_root) { char tmp[1024], *buf; size_t len, off; @@ -7038,6 +7169,8 @@ static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id, USEINFO(poolstats, 1, 1); USEINFO(userstats, 4, 2); USEINFO(workerstatus, 1, 1); + USEINFO(workqueue, 1, 0); + USEINFO(transfer, 0, 0); snprintf(tmp, sizeof(tmp), "%ctotalram=%"PRIu64, FLDSEP, tot); APPEND_REALLOC(buf, off, len, tmp); @@ -7046,28 +7179,6 @@ static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id, return buf; } -enum cmd_values { - CMD_UNSET, - CMD_REPLY, // Means something was wrong - send back reply - CMD_SHUTDOWN, - CMD_PING, - CMD_SHARELOG, - CMD_AUTH, - CMD_ADDUSER, - CMD_CHKPASS, - CMD_POOLSTAT, - CMD_USERSTAT, - CMD_BLOCK, - CMD_NEWID, - CMD_PAYMENTS, - CMD_WORKERS, - CMD_ALLUSERS, - CMD_HOMEPAGE, - CMD_DSP, - CMD_STATS, - CMD_END -}; - // TODO: limit access #define ACCESS_POOL "p" #define ACCESS_SYSTEM "s" @@ -7080,7 +7191,8 @@ static struct CMDS { char *cmd_str; bool noid; // doesn't require an id bool createdate; // requires a createdate - char *(*func)(PGconn *, char *, char *, tv_t *, char *, char *, char *, tv_t *); + char *(*func)(PGconn *, char *, char *, tv_t *, char *, char *, + char *, tv_t *, K_TREE *); char *access; } cmds[] = { { CMD_SHUTDOWN, "shutdown", true, false, NULL, ACCESS_SYSTEM }, @@ -7105,7 +7217,9 @@ static struct CMDS { { CMD_END, NULL, false, false, NULL, NULL } }; -static enum cmd_values breakdown(char *buf, int *which_cmds, char *cmd, char *id, tv_t *cd) +static enum cmd_values breakdown(K_TREE **trf_root, K_STORE **trf_store, + char *buf, int *which_cmds, char *cmd, + char *id, tv_t *cd) { char reply[1024] = ""; K_TREE_CTX ctx[1]; @@ -7113,6 +7227,8 @@ static enum cmd_values breakdown(char *buf, int *which_cmds, char *cmd, char *id char *cmdptr, *idptr, *data, *next, *eq; bool noid = false; + *trf_root = NULL; + *trf_store = NULL; *which_cmds = CMD_UNSET; *cmd = *id = '\0'; cd->tv_sec = 0; @@ -7155,6 +7271,8 @@ static enum cmd_values breakdown(char *buf, int *which_cmds, char *cmd, char *id return CMD_REPLY; } + *trf_root = new_ktree(); + *trf_store = k_new_store(transfer_free); next = data; if (next && strncmp(next, JSON_TRANSFER, JSON_TRANSFER_LEN) == 0) { json_t *json_data; @@ -7251,13 +7369,13 @@ static enum cmd_values breakdown(char *buf, int *which_cmds, char *cmd, char *id if (ok) STRNCPY(DATA_TRANSFER(item)->name, json_key); - if (!ok || find_in_ktree(transfer_root, item, cmp_transfer, ctx)) { + if (!ok || find_in_ktree(*trf_root, item, cmp_transfer, ctx)) { if (DATA_TRANSFER(item)->data != DATA_TRANSFER(item)->value) free(DATA_TRANSFER(item)->data); k_add_head(transfer_free, item); } else { - transfer_root = add_to_ktree(transfer_root, item, cmp_transfer); - k_add_head(transfer_store, item); + *trf_root = add_to_ktree(*trf_root, item, cmp_transfer); + k_add_head(*trf_store, item); } json_iter = json_object_iter_next(json_data, json_iter); } @@ -7282,19 +7400,19 @@ static enum cmd_values breakdown(char *buf, int *which_cmds, char *cmd, char *id STRNCPY(DATA_TRANSFER(item)->value, eq); DATA_TRANSFER(item)->data = DATA_TRANSFER(item)->value; - if (find_in_ktree(transfer_root, item, cmp_transfer, ctx)) { + if (find_in_ktree(*trf_root, item, cmp_transfer, ctx)) { if (DATA_TRANSFER(item)->data != DATA_TRANSFER(item)->value) free(DATA_TRANSFER(item)->data); k_add_head(transfer_free, item); } else { - transfer_root = add_to_ktree(transfer_root, item, cmp_transfer); - k_add_head(transfer_store, item); + *trf_root = add_to_ktree(*trf_root, item, cmp_transfer); + k_add_head(*trf_store, item); } } K_WUNLOCK(transfer_free); } if (cmds[*which_cmds].createdate) { - item = require_name("createdate", 10, NULL, reply, sizeof(reply)); + item = require_name(*trf_root, "createdate", 10, NULL, reply, sizeof(reply)); if (!item) return CMD_REPLY; @@ -7502,30 +7620,333 @@ static void *summariser(__maybe_unused void *arg) { pthread_detach(pthread_self()); - while (!summarizer_die && !db_load_complete) + while (!everyone_die && !db_load_complete) cksleep_ms(42); - while (!summarizer_die) { - sleep(19); + while (!everyone_die) { + sleep(13); - if (!summarizer_die) + if (!everyone_die) summarise_poolstats(); - if (!summarizer_die) + if (!everyone_die) summarise_userstats(); } return NULL; } -static void reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) +static void *socketer(__maybe_unused void *arg) +{ + proc_instance_t *pi = (proc_instance_t *)arg; + unixsock_t *us = &pi->us; + char *end, *ans = NULL, *rep = NULL, *buf = NULL, *dot; + char cmd[CMD_SIZ+1], id[ID_SIZ+1], reply[1024+1]; + char *last_auth = NULL, *reply_auth = NULL; + char *last_adduser = NULL, *reply_adduser = NULL; + char *last_chkpass = NULL, *reply_chkpass = NULL; + char *last_newid = NULL, *reply_newid = NULL; + char *last_web = NULL, *reply_web = NULL; + char *reply_last, duptype[CMD_SIZ+1]; + enum cmd_values cmdnum; + int sockd, which_cmds; + WORKQUEUE *workqueue; + K_STORE *trf_store; + K_TREE *trf_root; + K_ITEM *item; + size_t siz; + tv_t now, cd; + bool dup, want_first; + + pthread_detach(pthread_self()); + + while (!everyone_die && !db_auths_complete) + cksem_mswait(&socketer_sem, 420); + + want_first = true; + while (!everyone_die) { + if (buf) + dealloc(buf); + sockd = accept(us->sockd, NULL, NULL); + if (sockd < 0) { + LOGERR("Failed to accept on socket in listener"); + break; + } + + cmdnum = CMD_UNSET; + trf_root = NULL; + trf_store = NULL; + + buf = recv_unix_msg(sockd); + // Once we've read the message + setnow(&now); + if (buf) { + end = buf + strlen(buf) - 1; + // strip trailing \n and \r + while (end >= buf && (*end == '\n' || *end == '\r')) + *(end--) = '\0'; + } + if (!buf || !*buf) { + // An empty message wont get a reply + if (!buf) + LOGWARNING("Failed to get message in listener"); + else + LOGWARNING("Empty message in listener"); + } else { + if (want_first) { + ck_wlock(&fpm_lock); + first_pool_message = strdup(buf); + ck_wunlock(&fpm_lock); + want_first = false; + } + + /* For duplicates: + * Queued pool messages are handled by the queue code + * but since they reply ok.queued that message can + * be returned every time here + * System: repeat process them + * Web: current php web sends a timestamp of seconds + * so duplicate code will only trigger if the same + * message is sent within the same second and thus + * will effectively reduce the processing load for + * sequential duplicates + * adduser duplicates are handled by the DB code + * auth, chkpass, adduser, newid - remember individual + * last message and reply and repeat the reply without + * reprocessing the message + */ + dup = false; + if (last_auth && strcmp(last_auth, buf) == 0) { + reply_last = reply_auth; + dup = true; + } else if (last_chkpass && strcmp(last_chkpass, buf) == 0) { + reply_last = reply_chkpass; + dup = true; + } else if (last_adduser && strcmp(last_adduser, buf) == 0) { + reply_last = reply_adduser; + dup = true; + } else if (last_newid && strcmp(last_newid, buf) == 0) { + reply_last = reply_newid; + dup = true; + } else if (last_web && strcmp(last_web, buf) == 0) { + reply_last = reply_web; + dup = true; + } + if (dup) { + send_unix_msg(sockd, reply_last); + STRNCPY(duptype, buf); + dot = strchr(duptype, '.'); + if (dot) + *dot = '\0'; + snprintf(reply, sizeof(reply), "%s%ld,%ld.%s", + LOGDUP, now.tv_sec, now.tv_usec, duptype); + LOGFILE(reply); + LOGWARNING("Duplicate '%s' message received", duptype); + } else { + LOGFILE(buf); + cmdnum = breakdown(&trf_root, &trf_store, buf, &which_cmds, cmd, id, &cd); + switch (cmdnum) { + case CMD_REPLY: + snprintf(reply, sizeof(reply), "%s.%ld.?.", id, now.tv_sec); + send_unix_msg(sockd, reply); + break; + case CMD_SHUTDOWN: + LOGWARNING("Listener received shutdown message, terminating ckdb"); + snprintf(reply, sizeof(reply), "%s.%ld.ok.exiting", id, now.tv_sec); + send_unix_msg(sockd, reply); + break; + case CMD_PING: + LOGDEBUG("Listener received ping request"); + snprintf(reply, sizeof(reply), "%s.%ld.ok.pong", id, now.tv_sec); + send_unix_msg(sockd, reply); + break; + // Always process immediately: + case CMD_AUTH: + case CMD_CHKPASS: + case CMD_ADDUSER: + case CMD_NEWID: + case CMD_STATS: + ans = cmds[which_cmds].func(NULL, cmd, id, &now, + by_default, + (char *)__func__, + inet_default, + &cd, trf_root); + siz = strlen(ans) + strlen(id) + 32; + rep = malloc(siz); + snprintf(rep, siz, "%s.%ld.%s", id, now.tv_sec, ans); + send_unix_msg(sockd, rep); + free(ans); + ans = NULL; + switch (cmdnum) { + case CMD_AUTH: + if (last_auth) + free(last_auth); + last_auth = buf; + buf = NULL; + if (reply_auth) + free(reply_auth); + reply_auth = rep; + break; + case CMD_CHKPASS: + if (last_chkpass) + free(last_chkpass); + last_chkpass = buf; + buf = NULL; + if (reply_chkpass) + free(reply_chkpass); + reply_chkpass = rep; + break; + case CMD_ADDUSER: + if (last_adduser) + free(last_adduser); + last_adduser = buf; + buf = NULL; + if (reply_adduser) + free(reply_adduser); + reply_adduser = rep; + break; + case CMD_NEWID: + if (last_newid) + free(last_newid); + last_newid = buf; + buf = NULL; + if (reply_newid) + free(reply_newid); + reply_newid = rep; + break; + default: + free(rep); + } + rep = NULL; + break; + // Process, but reject (loading) until startup_complete + case CMD_HOMEPAGE: + case CMD_ALLUSERS: + case CMD_WORKERS: + case CMD_PAYMENTS: + case CMD_DSP: + if (!startup_complete) { + snprintf(reply, sizeof(reply), + "%s.%ld.loading.%s", + id, now.tv_sec, cmd); + send_unix_msg(sockd, reply); + } else { + ans = cmds[which_cmds].func(NULL, cmd, id, &now, + by_default, + (char *)__func__, + inet_default, + &cd, trf_root); + siz = strlen(ans) + strlen(id) + 32; + rep = malloc(siz); + snprintf(rep, siz, "%s.%ld.%s", id, now.tv_sec, ans); + send_unix_msg(sockd, rep); + free(ans); + ans = NULL; + if (cmdnum == CMD_DSP) + free(rep); + else { + if (last_web) + free(last_web); + last_web = buf; + buf = NULL; + if (reply_web) + free(reply_web); + reply_web = rep; + } + rep = NULL; + } + break; + // Always queue (ok.queued) + case CMD_SHARELOG: + case CMD_POOLSTAT: + case CMD_USERSTAT: + case CMD_BLOCK: + snprintf(reply, sizeof(reply), + "%s.%ld.ok.queued", + id, now.tv_sec); + send_unix_msg(sockd, reply); + + K_WLOCK(workqueue_free); + item = k_unlink_head(workqueue_free); + K_WUNLOCK(workqueue_free); + + workqueue = DATA_WORKQUEUE(item); + workqueue->buf = buf; + buf = NULL; + workqueue->which_cmds = which_cmds; + workqueue->cmdnum = cmdnum; + STRNCPY(workqueue->cmd, cmd); + STRNCPY(workqueue->id, id); + copy_tv(&(workqueue->now), &now); + STRNCPY(workqueue->by, by_default); + STRNCPY(workqueue->code, __func__); + STRNCPY(workqueue->inet, inet_default); + copy_tv(&(workqueue->cd), &cd); + workqueue->trf_root = trf_root; + trf_root = NULL; + workqueue->trf_store = trf_store; + trf_store = NULL; + + K_WLOCK(workqueue_free); + k_add_tail(workqueue_store, item); + K_WUNLOCK(workqueue_free); + + cksem_post(&workqueue_sem); + break; + // Code error + default: + LOGEMERG("%s() CODE ERROR unhandled message %d %.32s...", + __func__, cmdnum, buf); + snprintf(reply, sizeof(reply), + "%s.%ld.failed.code", + id, now.tv_sec); + send_unix_msg(sockd, reply); + break; + } + } + } + close(sockd); + + tick(); + + if (cmdnum == CMD_SHUTDOWN) + break; + + if (trf_root) + trf_root = free_ktree(trf_root, NULL); + if (trf_store) { + item = trf_store->head; + while (item) { + if (DATA_TRANSFER(item)->data != DATA_TRANSFER(item)->value) + free(DATA_TRANSFER(item)->data); + item = item->next; + } + K_WLOCK(transfer_free); + k_list_transfer_to_head(trf_store, transfer_free); + K_WUNLOCK(transfer_free); + trf_store = k_free_store(trf_store); + } + } + + if (buf) + dealloc(buf); + // TODO: if anyone cares, free all the dup buffers :P + close_unix_socket(us->sockd, us->path); + + return NULL; +} + +static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) { char cmd[CMD_SIZ+1], id[ID_SIZ+1]; enum cmd_values cmdnum; char *end, *ans; int which_cmds; + K_STORE *trf_store = NULL; + K_TREE *trf_root = NULL; K_ITEM *item; tv_t now, cd; + bool finished; // Once we've read the message setnow(&now); @@ -7541,8 +7962,18 @@ static void reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) else LOGERR("%s() Empty message line %"PRIu64, __func__, count); } else { + finished = false; + ck_wlock(&fpm_lock); + if (first_pool_message && strcmp(first_pool_message, buf) == 0) + finished = true; + ck_wunlock(&fpm_lock); + if (finished) { + LOGERR("%s() reload completed, ckpool queue match at line %"PRIu64, __func__, count); + return true; + } + LOGFILE(buf); - cmdnum = breakdown(buf, &which_cmds, cmd, id, &cd); + cmdnum = breakdown(&trf_root, &trf_store, buf, &which_cmds, cmd, id, &cd); switch (cmdnum) { // Ignore case CMD_REPLY: @@ -7569,9 +8000,10 @@ static void reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) case CMD_USERSTAT: case CMD_BLOCK: ans = cmds[which_cmds].func(conn, cmd, id, &now, - (char *)"code", + by_default, (char *)__func__, - (char *)"127.0.0.1", &cd); + inet_default, + &cd, trf_root); if (ans) free(ans); break; @@ -7582,19 +8014,25 @@ static void reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) break; } - K_WLOCK(transfer_free); - transfer_root = free_ktree(transfer_root, NULL); - item = transfer_store->head; - while (item) { - if (DATA_TRANSFER(item)->data != DATA_TRANSFER(item)->value) - free(DATA_TRANSFER(item)->data); - item = item->next; + if (trf_root) + trf_root = free_ktree(trf_root, NULL); + if (trf_store) { + item = trf_store->head; + while (item) { + if (DATA_TRANSFER(item)->data != DATA_TRANSFER(item)->value) + free(DATA_TRANSFER(item)->data); + item = item->next; + } + K_WLOCK(transfer_free); + k_list_transfer_to_head(trf_store, transfer_free); + K_WUNLOCK(transfer_free); + trf_store = k_free_store(trf_store); } - k_list_transfer_to_head(transfer_store, transfer_free); - K_WUNLOCK(transfer_free); } tick(); + + return false; } // Log files are every ... @@ -7605,7 +8043,7 @@ static void reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) /* If the reload start file is missing and -r was specified correctly: * touch the filename reported in "Failed to open 'filename'" * when ckdb aborts at the beginning of the reload */ -static void reload_from(tv_t *start) +static bool reload_from(tv_t *start) { PGconn *conn = NULL; char buf[DATE_BUFSIZ+1], run[DATE_BUFSIZ+1]; @@ -7613,7 +8051,7 @@ static void reload_from(tv_t *start) char *missingfirst = NULL, *missinglast = NULL; int missing_count; int processing; - bool finished = false; + bool finished = false, matched = false, ret = true; char *filename = NULL; char data[MAX_READ]; uint64_t count, total; @@ -7644,8 +8082,8 @@ static void reload_from(tv_t *start) processing++; count = 0; - while (fgets_unlocked(data, MAX_READ, fp)) - reload_line(conn, filename, ++count, data); + while (!matched && fgets_unlocked(data, MAX_READ, fp)) + matched = reload_line(conn, filename, ++count, data); if (ferror(fp)) { int err = errno; @@ -7660,6 +8098,8 @@ static void reload_from(tv_t *start) total += count; fclose(fp); free(filename); + if (matched) + break; start->tv_sec += ROLL_S; filename = rotating_filename(restorefrom, start->tv_sec); fp = fopen(filename, "r"); @@ -7715,167 +8155,102 @@ static void reload_from(tv_t *start) processing, processing == 1 ? "" : "s", total, total == 1 ? "" : "s"); + if (!matched) { + ck_wlock(&fpm_lock); + if (first_pool_message) { + LOGERR("%s() reload completed without finding ckpool queue match '%.32s'...", + __func__, first_pool_message); + LOGERR("%s() restart ckdb to resolve this", __func__); + ret = false; + } + ck_wunlock(&fpm_lock); + } + reloading = false; + + return ret; +} + +static void process_queued(K_ITEM *wq_item) +{ + static char *last_buf = NULL; + WORKQUEUE *workqueue; + K_ITEM *item; + char *ans; + + workqueue = DATA_WORKQUEUE(wq_item); + + // Simply ignore the (very rare) duplicates + if (!last_buf || strcmp(workqueue->buf, last_buf)) { + ans = cmds[workqueue->which_cmds].func(NULL, workqueue->cmd, workqueue->id, + &(workqueue->now), workqueue->by, + workqueue->code, workqueue->inet, + &(workqueue->cd), workqueue->trf_root); + free(ans); + } + + if (last_buf) + free(last_buf); + last_buf = workqueue->buf; + + workqueue->trf_root = free_ktree(workqueue->trf_root, NULL); + item = workqueue->trf_store->head; + while (item) { + if (DATA_TRANSFER(item)->data != DATA_TRANSFER(item)->value) + free(DATA_TRANSFER(item)->data); + item = item->next; + } + K_WLOCK(transfer_free); + k_list_transfer_to_head(workqueue->trf_store, transfer_free); + K_WUNLOCK(transfer_free); + workqueue->trf_store = k_free_store(workqueue->trf_store); + + K_WLOCK(workqueue_free); + k_add_head(workqueue_free, wq_item); + K_WUNLOCK(workqueue_free); } // TODO: equivalent of api_allow static void *listener(void *arg) { proc_instance_t *pi = (proc_instance_t *)arg; - unixsock_t *us = &pi->us; - char *end, *ans, *rep, *buf = NULL, *dot; - char *last_msg = NULL, *last_reply = NULL; - char cmd[CMD_SIZ+1], id[ID_SIZ+1], reply[1024+1]; - // Minimise the size in case of garbage - char duptype[CMD_SIZ+1]; - enum cmd_values cmdnum, last_cmd = 9001; - int sockd, which_cmds; - pthread_t summzer; - uint64_t counter = 0; - K_ITEM *item; - size_t siz; - tv_t now, cd; - bool dup; + pthread_t sock_pt; + pthread_t summ_pt; + K_ITEM *wq_item; + int qc; - create_pthread(&summzer, summariser, NULL); + create_pthread(&sock_pt, socketer, arg); + + create_pthread(&summ_pt, summariser, NULL); rename_proc(pi->sockname); if (!setup_data()) { + everyone_die = true; LOGEMERG("ABORTING"); return NULL; } - LOGWARNING("%s(): ckdb ready", __func__); - - startup_complete = true; - - while (true) { - dealloc(buf); - sockd = accept(us->sockd, NULL, NULL); - if (sockd < 0) { - LOGERR("Failed to accept on socket in listener"); - break; - } - - cmdnum = CMD_UNSET; - - buf = recv_unix_msg(sockd); - // Once we've read the message - setnow(&now); - if (buf) { - end = buf + strlen(buf) - 1; - // strip trailing \n and \r - while (end >= buf && (*end == '\n' || *end == '\r')) - *(end--) = '\0'; - } - if (!buf || !*buf) { - // An empty message wont get a reply - if (!buf) - LOGWARNING("Failed to get message in listener"); - else - LOGWARNING("Empty message in listener"); - } else { - /* For duplicates: - * System: shutdown and ping are always processed, - * so for any others, send a ping between them - * if you need to send the same message twice - * Web: if the pool didn't do anything since the original - * then the reply could be wrong for any reply that - * changes over time ... however if the pool is busy - * and we get the same request repeatedly, this will - * reduce the load - thus always send the same reply - * Pool: must not process it, must send back the same reply - * TODO: remember last message+reply per source - */ - if (last_msg && strcmp(last_msg, buf) == 0) { - dup = true; - // This means an exact duplicate of the last non-dup - snprintf(reply, sizeof(reply), "%s%ld,%ld", LOGDUP, now.tv_sec, now.tv_usec); - LOGFILE(reply); - cmdnum = last_cmd; - - STRNCPY(duptype, buf); - dot = strchr(duptype, '.'); - if (dot) - *dot = '\0'; - LOGWARNING("Duplicate '%s' message received", duptype); - } else { - dup = false; - LOGFILE(buf); - cmdnum = breakdown(buf, &which_cmds, cmd, id, &cd); - last_cmd = cmdnum; - } - switch (cmdnum) { - case CMD_REPLY: - if (dup) - send_unix_msg(sockd, last_reply); - else { - snprintf(reply, sizeof(reply), "%s.%ld.?.", id, now.tv_sec); - if (last_reply) - free(last_reply); - last_reply = strdup(reply); - send_unix_msg(sockd, reply); - } - break; - case CMD_SHUTDOWN: - LOGWARNING("Listener received shutdown message, terminating ckdb"); - snprintf(reply, sizeof(reply), "%s.%ld.ok.exiting", id, now.tv_sec); - send_unix_msg(sockd, reply); - break; - case CMD_PING: - LOGDEBUG("Listener received ping request"); - // Generate a new reply each time even on dup - snprintf(reply, sizeof(reply), "%s.%ld.ok.pong", id, now.tv_sec); - send_unix_msg(sockd, reply); - break; - default: - if (dup) - send_unix_msg(sockd, last_reply); - else { - ans = cmds[which_cmds].func(NULL, cmd, id, &now, - (char *)"code", - (char *)__func__, - (char *)"127.0.0.1", &cd); - siz = strlen(ans) + strlen(id) + 32; - rep = malloc(siz); - snprintf(rep, siz, "%s.%ld.%s", id, now.tv_sec, ans); - free(ans); - ans = NULL; - if (last_reply) - free(last_reply); - last_reply = strdup(rep); - send_unix_msg(sockd, rep); - free(rep); - rep = NULL; - } - break; - } - } - close(sockd); + K_RLOCK(workqueue_store); + qc = workqueue_store->count; + K_RUNLOCK(workqueue_store); - counter++; - tick(); + LOGWARNING("%s(): ckdb ready, queue %d", __func__, qc); - if (cmdnum == CMD_SHUTDOWN) - break; + startup_complete = true; - K_WLOCK(transfer_free); - transfer_root = free_ktree(transfer_root, NULL); - item = transfer_store->head; - while (item) { - if (DATA_TRANSFER(item)->data != DATA_TRANSFER(item)->value) - free(DATA_TRANSFER(item)->data); - item = item->next; - } - k_list_transfer_to_head(transfer_store, transfer_free); - K_WUNLOCK(transfer_free); + // Process queued work + while (!everyone_die) { + K_WLOCK(workqueue_store); + wq_item = k_unlink_head(workqueue_store); + K_WUNLOCK(workqueue_store); + if (wq_item) { + process_queued(wq_item); + tick(); + } else + cksem_mswait(&workqueue_sem, 420); } - dealloc(buf); - if (last_reply) - free(last_reply); - close_unix_socket(us->sockd, us->path); return NULL; } @@ -7978,7 +8353,6 @@ int main(int argc, char **argv) } if (!ckp.socket_dir) { -// ckp.socket_dir = strdup("/tmp/"); ckp.socket_dir = strdup("/opt/"); realloc_strcat(&ckp.socket_dir, ckp.name); } From c11b2c11f3e8e6ba63c19832592e2043da2e5cb5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 14 Aug 2014 22:45:47 +1000 Subject: [PATCH 13/20] Log ckdb messages before adding them to the queue of messages to send to it to ensure messages continue to be logged as generated even if they're queued to be sent to ckdb --- src/ckpool.c | 100 ++--------------------------------------------- src/ckpool.h | 6 +-- src/stratifier.c | 65 +++++++++++++++++++----------- 3 files changed, 49 insertions(+), 122 deletions(-) diff --git a/src/ckpool.c b/src/ckpool.c index 77bf20cf..2793f258 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -507,110 +507,18 @@ out: return buf; } -static const char *invalid_unknown = " (unknown reason)"; -static const char *invalid_toodeep = " >9 levels, recursion?"; - -#define first_invalid(_json_data) _first_invalid(_json_data, 0) - -static char *_first_invalid(json_t *json_data, int level) -{ - const char *json_key, *json_str; - json_t *json_value; - void *json_iter; - int json_typ; - char buf[512], *inside; - bool found; - - if (level > 9) - return strdup(invalid_toodeep); - - buf[0] = '\0'; - found = false; - json_iter = json_object_iter(json_data); - while (!found && json_iter) { - json_key = json_object_iter_key(json_iter); - json_value = json_object_iter_value(json_iter); - json_typ = json_typeof(json_value); - switch(json_typ) { - case JSON_STRING: - json_str = json_string_value(json_value); - if (json_str == NULL) { - snprintf(buf, sizeof(buf), - " %s is NULL", json_key); - found = true; - } - break; - case JSON_REAL: - case JSON_INTEGER: - case JSON_TRUE: - case JSON_FALSE: - break; - case JSON_ARRAY: - inside = _first_invalid(json_value, level+1); - if (inside != invalid_unknown) { - snprintf(buf, sizeof(buf), - " %s : [%s ]", json_key, inside); - free(inside); - found = true; - } - break; - case JSON_NULL: - snprintf(buf, sizeof(buf), - " %s is NULL", json_key); - found = true; - break; - default: - snprintf(buf, sizeof(buf), - " unknown type %d for %s", - json_typ, json_key); - found = true; - break; - } - if (!found) - json_iter = json_object_iter_next(json_data, json_iter); - } - - if (!*buf) { - if (level > 0) - return (char *)invalid_unknown; - else - return strdup(invalid_unknown); - } else - return strdup(buf); -} - -/* Send a json msg to ckdb with its idmsg and return the response, consuming - * the json on success */ -char *_json_ckdb_call(const ckpool_t *ckp, const char *idmsg, json_t *val, bool logged, - const char *file, const char *func, const int line) +/* Send a json msg to ckdb and return the response */ +char *_ckdb_msg_call(const ckpool_t *ckp, char *msg, const char *file, const char *func, + const int line) { - char *msg = NULL, *dump, *buf = NULL; - - dump = json_dumps(val, JSON_COMPACT); - if (unlikely(!dump)) { - char *invalid = first_invalid(val); - LOGWARNING("Json dump failed in json_ckdb_call from %s %s:%d%s", file, func, line, invalid); - free(invalid); - return buf; - } - ASPRINTF(&msg, "%s.id.json=%s", idmsg, dump); - if (!logged) { - char logname[512]; + char *buf = NULL; - snprintf(logname, 511, "%s%s", ckp->logdir, ckp->ckdb_name); - rotating_log(logname, msg); - } - free(dump); LOGDEBUG("Sending ckdb: %s", msg); buf = _send_recv_ckdb(ckp, msg, file, func, line); LOGDEBUG("Received from ckdb: %s", buf); - free(msg); - if (likely(buf)) - json_decref(val); return buf; } - json_t *json_rpc_call(connsock_t *cs, const char *rpc_req) { char *http_req = NULL; diff --git a/src/ckpool.h b/src/ckpool.h index 43b14fab..c27c042b 100644 --- a/src/ckpool.h +++ b/src/ckpool.h @@ -174,9 +174,9 @@ char *_send_recv_proc(proc_instance_t *pi, const char *msg, const char *file, co #define send_recv_proc(pi, msg) _send_recv_proc(pi, msg, __FILE__, __func__, __LINE__) char *_send_recv_ckdb(const ckpool_t *ckp, const char *msg, const char *file, const char *func, const int line); #define send_recv_ckdb(ckp, msg) _send_recv_ckdb(ckp, msg, __FILE__, __func__, __LINE__) -char *_json_ckdb_call(const ckpool_t *ckp, const char *idmsg, json_t *val, bool logged, - const char *file, const char *func, const int line); -#define json_ckdb_call(ckp, idmsg, val, logged) _json_ckdb_call(ckp, idmsg, val, logged, __FILE__, __func__, __LINE__) +char *_ckdb_msg_call(const ckpool_t *ckp, char *msg, const char *file, const char *func, + const int line); +#define ckdb_msg_call(ckp, msg) _ckdb_msg_call(ckp, msg, __FILE__, __func__, __LINE__) json_t *json_rpc_call(connsock_t *cs, const char *rpc_req); diff --git a/src/stratifier.c b/src/stratifier.c index ed49e38c..c8383eba 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -170,13 +170,6 @@ struct json_params { typedef struct json_params json_params_t; -struct ckdb_msg { - json_t *val; - int idtype; -}; - -typedef struct ckdb_msg ckdb_msg_t; - /* Stratum json messages with their associated client id */ struct smsg { json_t *json_msg; @@ -415,12 +408,32 @@ static void purge_share_hashtable(int64_t wb_id) static char *status_chars = "|/-\\"; +/* Absorbs the json and generates a ckdb json message, logs it to the ckdb + * log and returns the malloced message. */ +static char *ckdb_msg(ckpool_t *ckp, json_t *val, const int idtype) +{ + char *json_msg = json_dumps(val, JSON_COMPACT); + char logname[512]; + char *ret = NULL; + + if (unlikely(!json_msg)) + goto out; + ASPRINTF(&ret, "%s.id.json=%s", ckdb_ids[idtype], json_msg); + free(json_msg); +out: + json_decref(val); + snprintf(logname, 511, "%s%s", ckp->logdir, ckp->ckdb_name); + rotating_log(logname, ret); + return ret; +} + static void _ckdbq_add(ckpool_t *ckp, const int idtype, json_t *val, const char *file, const char *func, const int line) { - static int counter = 0; static time_t time_counter; - ckdb_msg_t *msg; + static int counter = 0; + + char *json_msg; time_t now_t; char ch; @@ -441,10 +454,13 @@ static void _ckdbq_add(ckpool_t *ckp, const int idtype, json_t *val, const char if (ckp->standalone) return json_decref(val); - msg = ckalloc(sizeof(ckdb_msg_t)); - msg->val = val; - msg->idtype = idtype; - ckmsgq_add(ckdbq, msg); + json_msg = ckdb_msg(ckp, val, idtype); + if (unlikely(!json_msg)) { + LOGWARNING("Failed to dump json from %s %s:%d", file, func, line); + return; + } + + ckmsgq_add(ckdbq, json_msg); } #define ckdbq_add(ckp, idtype, val) _ckdbq_add(ckp, idtype, val, __FILE__, __func__, __LINE__) @@ -1252,10 +1268,10 @@ static user_instance_t *authorise_user(const char *workername) static bool send_recv_auth(stratum_instance_t *client) { ckpool_t *ckp = client->ckp; + char *buf, *json_msg; char cdfield[64]; bool ret = false; json_t *val; - char *buf; ts_t now; ts_realtime(&now); @@ -1272,7 +1288,13 @@ static bool send_recv_auth(stratum_instance_t *client) "createby", "code", "createcode", __func__, "createinet", client->address); - buf = json_ckdb_call(ckp, ckdb_ids[ID_AUTH], val, false); + json_msg = ckdb_msg(ckp, val, ID_AUTH); + if (unlikely(!json_msg)) { + LOGWARNING("Failed to dump json in send_recv_auth"); + return ret; + } + buf = ckdb_msg_call(ckp, json_msg); + free(json_msg); if (likely(buf)) { char *secondaryuserid, *response = alloca(128); @@ -1286,10 +1308,8 @@ static bool send_recv_auth(stratum_instance_t *client) client->secondaryuserid = strdup(secondaryuserid); ret = true; } - } else { + } else LOGWARNING("Got no auth response from ckdb :("); - json_decref(val); - } return ret; } @@ -2158,14 +2178,13 @@ out: } -static void ckdbq_process(ckpool_t *ckp, ckdb_msg_t *data) +static void ckdbq_process(ckpool_t *ckp, char *msg) { static bool failed = false; - bool logged = false; char *buf = NULL; while (!buf) { - buf = json_ckdb_call(ckp, ckdb_ids[data->idtype], data->val, logged); + buf = ckdb_msg_call(ckp, msg); if (unlikely(!buf)) { if (!failed) { failed = true; @@ -2173,13 +2192,13 @@ static void ckdbq_process(ckpool_t *ckp, ckdb_msg_t *data) } sleep(5); } - logged = true; } + free(msg); if (failed) { failed = false; LOGWARNING("Successfully resumed talking to ckdb"); } - LOGINFO("Got %s ckdb response: %s", ckdb_ids[data->idtype], buf); + LOGINFO("Got ckdb response: %s", buf); free(buf); } From a1ffb3656c7af452ac21b3be2f90e1dc819259cf Mon Sep 17 00:00:00 2001 From: kanoi Date: Fri, 15 Aug 2014 08:21:42 +1000 Subject: [PATCH 14/20] sql - remove old versions so you must start at v0.6 --- sql/v0.1-v0.2.sql | 40 ---------------- sql/v0.2-v0.3.sql | 115 ---------------------------------------------- sql/v0.3-v0.4.sql | 41 ----------------- sql/v0.4-v0.5.sql | 42 ----------------- sql/v0.6.txt | 17 ------- 5 files changed, 255 deletions(-) delete mode 100644 sql/v0.1-v0.2.sql delete mode 100644 sql/v0.2-v0.3.sql delete mode 100644 sql/v0.3-v0.4.sql delete mode 100644 sql/v0.4-v0.5.sql delete mode 100644 sql/v0.6.txt diff --git a/sql/v0.1-v0.2.sql b/sql/v0.1-v0.2.sql deleted file mode 100644 index 0d8d8e23..00000000 --- a/sql/v0.1-v0.2.sql +++ /dev/null @@ -1,40 +0,0 @@ -SET SESSION AUTHORIZATION 'postgres'; - -BEGIN transaction; - -DO $$ -DECLARE ver TEXT; -BEGIN - - UPDATE version set version='0.2' where vlock=1 and version='0.1'; - - IF found THEN - RETURN; - END IF; - - SELECT version into ver from version - WHERE vlock=1; - - RAISE EXCEPTION 'Wrong DB version - expect "0.1" - found "%"', ver; - -END $$; - -ALTER TABLE ONLY poolstats - ADD COLUMN elapsed bigint DEFAULT 0 NOT NULL; - -CREATE TABLE userstats ( - poolinstance character varying(256) NOT NULL, - userid bigint NOT NULL, - elapsed bigint DEFAULT 0 NOT NULL, - hashrate float NOT NULL, - hashrate5m float NOT NULL, - hashrate1hr float NOT NULL, - hashrate24hr float NOT NULL, - createdate timestamp with time zone NOT NULL, - createby character varying(64) DEFAULT ''::character varying NOT NULL, - createcode character varying(128) DEFAULT ''::character varying NOT NULL, - createinet character varying(128) DEFAULT ''::character varying NOT NULL, - PRIMARY KEY (poolinstance, userid, createdate) -); - -END transaction; diff --git a/sql/v0.2-v0.3.sql b/sql/v0.2-v0.3.sql deleted file mode 100644 index f22cff78..00000000 --- a/sql/v0.2-v0.3.sql +++ /dev/null @@ -1,115 +0,0 @@ -SET SESSION AUTHORIZATION 'postgres'; - -BEGIN transaction; - -DO $$ -DECLARE ver TEXT; -BEGIN - - UPDATE version set version='0.3' where vlock=1 and version='0.2'; - - IF found THEN - RETURN; - END IF; - - SELECT version into ver from version - WHERE vlock=1; - - RAISE EXCEPTION 'Wrong DB version - expect "0.2" - found "%"', ver; - -END $$; - -DROP TABLE sharesummary; - -CREATE TABLE sharesummary ( - userid bigint NOT NULL, - workername character varying(256) NOT NULL, - workinfoid bigint NOT NULL, - diffacc float NOT NULL, - diffsta float NOT NULL, - diffdup float NOT NULL, - diffhi float NOT NULL, - diffrej float NOT NULL, - shareacc float NOT NULL, - sharesta float NOT NULL, - sharedup float NOT NULL, - sharehi float NOT NULL, - sharerej float NOT NULL, - sharecount bigint NOT NULL, - errorcount bigint NOT NULL, - firstshare timestamp with time zone NOT NULL, - lastshare timestamp with time zone NOT NULL, - complete char NOT NULL, - createdate timestamp with time zone NOT NULL, - createby character varying(64) NOT NULL, - createcode character varying(128) NOT NULL, - createinet character varying(128) NOT NULL, - modifydate timestamp with time zone NOT NULL, - modifyby character varying(64) NOT NULL, - modifycode character varying(128) NOT NULL, - modifyinet character varying(128) NOT NULL, - PRIMARY KEY (userid, workername, workinfoid) -); - -DROP TABLE blocksummary; - -CREATE TABLE workmarkers ( - markerid bigint NOT NULL, - workinfoidend bigint NOT NULL, - workinfoidstart bigint NOT NULL, - description character varying(256) DEFAULT ''::character varying NOT NULL, - createdate timestamp with time zone NOT NULL, - createby character varying(64) DEFAULT ''::character varying NOT NULL, - createcode character varying(128) DEFAULT ''::character varying NOT NULL, - createinet character varying(128) DEFAULT ''::character varying NOT NULL, - expirydate timestamp with time zone DEFAULT '6666-06-06 06:06:06+00', - PRIMARY KEY (workinfoidstart) -); -CREATE UNIQUE INDEX workmarkersid ON workmarkers USING btree (markerid); - -CREATE TABLE markersummary ( - markerid bigint NOT NULL, - userid bigint NOT NULL, - workername character varying(256) NOT NULL, - diffacc float NOT NULL, - diffsta float NOT NULL, - diffdup float NOT NULL, - diffhi float NOT NULL, - diffrej float NOT NULL, - shareacc float NOT NULL, - sharesta float NOT NULL, - sharedup float NOT NULL, - sharehi float NOT NULL, - sharerej float NOT NULL, - sharecount bigint NOT NULL, - errorcount bigint NOT NULL, - firstshare timestamp with time zone NOT NULL, - lastshare timestamp with time zone NOT NULL, - complete char NOT NULL, - createdate timestamp with time zone NOT NULL, - createby character varying(64) NOT NULL, - createcode character varying(128) NOT NULL, - createinet character varying(128) NOT NULL, - modifydate timestamp with time zone NOT NULL, - modifyby character varying(64) NOT NULL, - modifycode character varying(128) NOT NULL, - modifyinet character varying(128) NOT NULL, - PRIMARY KEY (markerid, userid, workername) -); - -ALTER TABLE ONLY eventlog - ADD COLUMN poolinstance character varying(256) NOT NULL; - -ALTER TABLE ONLY auths - ADD COLUMN poolinstance character varying(256) DEFAULT ''::character varying NOT NULL; - -ALTER TABLE ONLY auths - ALTER COLUMN poolinstance DROP DEFAULT; - -ALTER TABLE ONLY userstats - ADD COLUMN workername character varying(256) NOT NULL; - -ALTER TABLE ONLY poolstats - ALTER COLUMN elapsed DROP DEFAULT; - -END transaction; diff --git a/sql/v0.3-v0.4.sql b/sql/v0.3-v0.4.sql deleted file mode 100644 index a6964ee4..00000000 --- a/sql/v0.3-v0.4.sql +++ /dev/null @@ -1,41 +0,0 @@ -SET SESSION AUTHORIZATION 'postgres'; - -BEGIN transaction; - -DO $$ -DECLARE ver TEXT; -BEGIN - - UPDATE version set version='0.4' where vlock=1 and version='0.3'; - - IF found THEN - RETURN; - END IF; - - SELECT version into ver from version - WHERE vlock=1; - - RAISE EXCEPTION 'Wrong DB version - expect "0.3" - found "%"', ver; - -END $$; - -DROP TABLE userstats; - -CREATE TABLE userstats ( - userid bigint NOT NULL, - workername character varying(256) NOT NULL, - elapsed bigint NOT NULL, - hashrate float NOT NULL, - hashrate5m float NOT NULL, - hashrate1hr float NOT NULL, - hashrate24hr float NOT NULL, - summarylevel char NOT NULL, - statsdate timestamp with time zone NOT NULL, - createdate timestamp with time zone NOT NULL, - createby character varying(64) DEFAULT ''::character varying NOT NULL, - createcode character varying(128) DEFAULT ''::character varying NOT NULL, - createinet character varying(128) DEFAULT ''::character varying NOT NULL, - PRIMARY KEY (userid, workername, summarylevel, statsdate) -); - -END transaction; diff --git a/sql/v0.4-v0.5.sql b/sql/v0.4-v0.5.sql deleted file mode 100644 index 57e74b69..00000000 --- a/sql/v0.4-v0.5.sql +++ /dev/null @@ -1,42 +0,0 @@ -SET SESSION AUTHORIZATION 'postgres'; - -BEGIN transaction; - -DO $$ -DECLARE ver TEXT; -BEGIN - - UPDATE version set version='0.5' where vlock=1 and version='0.4'; - - IF found THEN - RETURN; - END IF; - - SELECT version into ver from version - WHERE vlock=1; - - RAISE EXCEPTION 'Wrong DB version - expect "0.4" - found "%"', ver; - -END $$; - -DROP TABLE userstats; - -CREATE TABLE userstats ( - userid bigint NOT NULL, - workername character varying(256) NOT NULL, - elapsed bigint NOT NULL, - hashrate float NOT NULL, - hashrate5m float NOT NULL, - hashrate1hr float NOT NULL, - hashrate24hr float NOT NULL, - summarylevel char NOT NULL, - summarycount integer NOT NULL, - statsdate timestamp with time zone NOT NULL, - createdate timestamp with time zone NOT NULL, - createby character varying(64) DEFAULT ''::character varying NOT NULL, - createcode character varying(128) DEFAULT ''::character varying NOT NULL, - createinet character varying(128) DEFAULT ''::character varying NOT NULL, - PRIMARY KEY (userid, workername, summarylevel, statsdate) -); - -END transaction; diff --git a/sql/v0.6.txt b/sql/v0.6.txt deleted file mode 100644 index e3f6b032..00000000 --- a/sql/v0.6.txt +++ /dev/null @@ -1,17 +0,0 @@ -To update to 0.6: -1) stop ckdb and ckpool -2) connect to postgres and delete the contents of all the tables except: - users, idcontrol, version - e.g. in psql to see all the table row counts: \i tables.sql - and to delete the rows from a table: delete from auths; -3) in pgsql: update version set version='0.6'; -4) rename all your ckdb20140*.log files using the src/relog.sh script -5) start ckdb -6) wait for ckdb to say it is ready - i.e. wait for it to reload all the - ckdb20140*.log files -7) start ckpool - -You can speed up step 6) if you don't care about losing the contents of the -DB forever: just go to the log directory and rename all the ckdb20140*.log -files something like: rename ".log" ".ignore" ckdb20140*.log -(or delete them) From 1bc8c20ef7e6279e60007ac43a5d74dbe887f610 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 15 Aug 2014 10:16:08 +1000 Subject: [PATCH 15/20] Give a more descriptive authorisation error message to miners when the database is offline --- src/stratifier.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index c8383eba..6fd372d7 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1265,12 +1265,12 @@ static user_instance_t *authorise_user(const char *workername) * and get SUID parameters back. We don't add these requests to the ckdbqueue * since we have to wait for the response but this is done from the authoriser * thread so it won't hold anything up but other authorisations. */ -static bool send_recv_auth(stratum_instance_t *client) +static int send_recv_auth(stratum_instance_t *client) { ckpool_t *ckp = client->ckp; char *buf, *json_msg; char cdfield[64]; - bool ret = false; + int ret = 1; json_t *val; ts_t now; @@ -1306,15 +1306,18 @@ static bool send_recv_auth(stratum_instance_t *client) response, secondaryuserid); if (!safecmp(response, "ok") && secondaryuserid) { client->secondaryuserid = strdup(secondaryuserid); - ret = true; + ret = 0; } - } else + } else { + ret = -1; LOGWARNING("Got no auth response from ckdb :("); + } return ret; } -static json_t *parse_authorise(stratum_instance_t *client, json_t *params_val, json_t **err_val, const char *address) +static json_t *parse_authorise(stratum_instance_t *client, json_t *params_val, json_t **err_val, + const char *address, int *errnum) { bool ret = false; const char *buf; @@ -1354,8 +1357,11 @@ static json_t *parse_authorise(stratum_instance_t *client, json_t *params_val, j client->workername = strdup(buf); if (client->ckp->standalone) ret = true; - else - ret = send_recv_auth(client); + else { + *errnum = send_recv_auth(client); + if (!*errnum) + ret = true; + } client->authorised = ret; if (client->authorised) inc_worker(client->user_instance); @@ -2147,7 +2153,7 @@ static void sauth_process(ckpool_t *ckp, json_params_t *jp) { json_t *result_val, *json_msg, *err_val = NULL; stratum_instance_t *client; - int client_id; + int client_id, errnum = 0; client_id = jp->client_id; @@ -2159,15 +2165,19 @@ static void sauth_process(ckpool_t *ckp, json_params_t *jp) LOGINFO("Authoriser failed to find client id %d in hashtable!", client_id); goto out; } - result_val = parse_authorise(client, jp->params, &err_val, jp->address); + result_val = parse_authorise(client, jp->params, &err_val, jp->address, &errnum); if (json_is_true(result_val)) { char *buf; ASPRINTF(&buf, "Authorised, welcome to %s %s!", ckp->name, client->user_instance->username); stratum_send_message(client, buf); - } else - stratum_send_message(client, "Failed authorisation :("); + } else { + if (errnum < 0) + stratum_send_message(client, "Authorisations temporarily offline :("); + else + stratum_send_message(client, "Failed authorisation :("); + } json_msg = json_object(); json_object_set_new_nocheck(json_msg, "result", result_val); json_object_set_new_nocheck(json_msg, "error", err_val ? err_val : json_null()); From d8afef7442ba4151d73326e41e7498c55d47c3cb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 15 Aug 2014 13:53:39 +1000 Subject: [PATCH 16/20] Add sample ckpool.conf --- ckpool.conf | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 ckpool.conf diff --git a/ckpool.conf b/ckpool.conf new file mode 100644 index 00000000..fcd1d7bb --- /dev/null +++ b/ckpool.conf @@ -0,0 +1,22 @@ +{ +"btcd" : [ + { + "url" : "localhost:8332", + "auth" : "user", + "pass" : "pass" + }, + { + "url" : "backup:8332", + "auth" : "user", + "pass" : "pass" + } +], +"btcaddress" : "15qSxP1SQcUX3o4nhkfdbgyoWEFMomJ4rZ", +"btcsig" : "/mined by ck/", +"blockpoll" : 500, +"update_interval" : 30, +"serverurl" : "ckpool.org:3333", +"mindiff" : 1, +"startdiff" : 1, +"logdir" : "logs" +} From 748ebfff42d8cd24d2dd215ca8e4fd973ab651a3 Mon Sep 17 00:00:00 2001 From: kanoi Date: Fri, 15 Aug 2014 14:11:56 +1000 Subject: [PATCH 17/20] ckdb - shutdown all threads --- src/ckdb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ckdb.c b/src/ckdb.c index 005da811..ee6e5592 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -7754,6 +7754,7 @@ static void *socketer(__maybe_unused void *arg) LOGWARNING("Listener received shutdown message, terminating ckdb"); snprintf(reply, sizeof(reply), "%s.%ld.ok.exiting", id, now.tv_sec); send_unix_msg(sockd, reply); + everyone_die = true; break; case CMD_PING: LOGDEBUG("Listener received ping request"); @@ -7909,9 +7910,6 @@ static void *socketer(__maybe_unused void *arg) tick(); - if (cmdnum == CMD_SHUTDOWN) - break; - if (trf_root) trf_root = free_ktree(trf_root, NULL); if (trf_store) { From 354d5511f40e5cb53675b7b1b38cc370b0a94e1c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 15 Aug 2014 14:14:18 +1000 Subject: [PATCH 18/20] Add sample ckproxy.conf --- ckproxy.conf | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 ckproxy.conf diff --git a/ckproxy.conf b/ckproxy.conf new file mode 100644 index 00000000..af528c1d --- /dev/null +++ b/ckproxy.conf @@ -0,0 +1,19 @@ +{ +"proxy" : [ + { + "url" : "ckpool.org:3333", + "auth" : "user", + "pass" : "pass" + }, + { + "url" : "backup.ckpool.org:3333", + "auth" : "user", + "pass" : "pass" + } +], +"update_interval" : 30, +"serverurl" : "192.168.1.100:3334", +"mindiff" : 1, +"startdiff" : 1, +"logdir" : "logs" +} From 7f5de8a9a13e87e9a7d8cac106c5acdce4287f71 Mon Sep 17 00:00:00 2001 From: kanoi Date: Fri, 15 Aug 2014 16:38:57 +1000 Subject: [PATCH 19/20] ckdb - allow '-' in email domains --- src/ckdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ckdb.c b/src/ckdb.c index ee6e5592..0ba6f981 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -643,7 +643,7 @@ static char *first_pool_message; static sem_t socketer_sem; static const char *userpatt = "^[!-~]*$"; // no spaces -static const char *mailpatt = "^[A-Za-z0-9_-][A-Za-z0-9_\\.-]*@[A-Za-z0-9][A-Za-z0-9\\.]*[A-Za-z0-9]$"; +static const char *mailpatt = "^[A-Za-z0-9_-][A-Za-z0-9_\\.-]*@[A-Za-z0-9][A-Za-z0-9\\.-]*[A-Za-z0-9]$"; static const char *idpatt = "^[_A-Za-z][_A-Za-z0-9]*$"; static const char *intpatt = "^[0-9][0-9]*$"; static const char *hashpatt = "^[A-Fa-f0-9]*$"; From 0117754b9019b624a49d0f54e5fe003fa3628c07 Mon Sep 17 00:00:00 2001 From: kanoi Date: Sat, 16 Aug 2014 09:50:35 +1000 Subject: [PATCH 20/20] php - disallow '.' or '_' in username --- pool/page_reg.php | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/pool/page_reg.php b/pool/page_reg.php index 7b7345da..fab55747 100644 --- a/pool/page_reg.php +++ b/pool/page_reg.php @@ -75,33 +75,47 @@ function safepass($pass) function show_reg($menu, $name, $u) { $user = getparam('user', false); - $mail = getparam('mail', false); + $mail = trim(getparam('mail', false)); $pass = getparam('pass', false); $pass2 = getparam('pass2', false); $data = array(); + + if (nuem($user)) + $data['user'] = ''; + else + $data['user'] = $user; + + if (nuem($mail)) + $data['mail'] = ''; + else + $data['mail'] = $mail; + $ok = true; - if ($user === NULL && $mail === NULL && $pass === NULL && $pass2 === NULL) - $ok = false; + if (nuem($user) || nuem($mail) || nuem($pass) || nuem($pass2)) + $ok = false; else { - if ($user !== NULL) - $data['user'] = $user; - else - $ok = false; - if ($mail !== NULL) - $data['mail'] = $mail; - else - $ok = false; - if ($pass === NULL || safepass($pass) !== true) + if (safepass($pass) !== true) { $ok = false; - $data['error'] = "Password is unsafe - requires 6 or more chars, including upper+lower+digits"; - } elseif ($pass2 === NULL || $pass2 != $pass) + $data['error'] = "Password is unsafe - requires 6 or more characters, including
" . + "at least one of each uppercase, lowercase and digits"; + } + elseif ($pass2 != $pass) { $ok = false; $data['error'] = "Passwords don't match"; } + + $orig = $user; + $user = preg_replace('/[_\\.]/', '', $orig); + if ($user != $orig) + { + $ok = false; + $data['error'] = "Username cannot include '.' or '_'"; + $data['user'] = $user; + } } if ($ok === true)