char *stratum_recv_line(struct stratum_ctx *sctx) { ssize_t len, buflen; char *tok, *sret = NULL; if (!strstr(sctx->sockbuf, "\n")) { bool ret = true; time_t rstart; time(&rstart); if (!socket_full(sctx->sock, 60)) { applog(LOG_ERR, "stratum_recv_line timed out"); goto out; } do { char s[RBUFSIZE]; ssize_t n; memset(s, 0, RBUFSIZE); n = recv(sctx->sock, s, RECVSIZE, 0); if (!n) { ret = false; break; } if (n < 0) { if (!socket_blocks() || !socket_full(sctx->sock, 1)) { ret = false; break; } } else stratum_buffer_append(sctx, s); } while (time(NULL) - rstart < 60 && !strstr(sctx->sockbuf, "\n")); if (!ret) { applog(LOG_ERR, "stratum_recv_line failed"); goto out; } } buflen = (ssize_t)strlen(sctx->sockbuf); tok = strtok(sctx->sockbuf, "\n"); if (!tok) { applog(LOG_ERR, "stratum_recv_line failed to parse a newline-terminated string"); goto out; } sret = strdup(tok); len = (ssize_t)strlen(sret); if (buflen > len + 1) memmove(sctx->sockbuf, sctx->sockbuf + len + 1, buflen - len + 1); else sctx->sockbuf[0] = '\0'; out: if (sret && opt_protocol) applog(LOG_DEBUG, "< %s", sret); return sret; }
/* Check to see if Santa's been good to you */ bool sock_full(struct pool *pool) { if (strlen(pool->sockbuf)) return true; return (socket_full(pool, false)); }
bool stratum_subscribe(struct stratum_ctx *sctx) { if(jsonrpc_2) return true; char *s, *sret = NULL; const char *sid, *xnonce1; int xn2_size; json_t *val = NULL, *res_val, *err_val; json_error_t err; bool ret = false, retry = false; start: s = (char*)malloc(128 + (sctx->session_id ? strlen(sctx->session_id) : 0)); if (retry) sprintf(s, "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": []}"); else if (sctx->session_id) sprintf(s, "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": [\"" USER_AGENT "\", \"%s\"]}", sctx->session_id); else sprintf(s, "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": [\"" USER_AGENT "\"]}"); if (!stratum_send_line(sctx, s)) goto out; if (!socket_full(sctx->sock, 30)) { applog(LOG_ERR, "stratum_subscribe timed out"); goto out; } sret = stratum_recv_line(sctx); if (!sret) goto out; val = JSON_LOADS(sret, &err); free(sret); if (!val) { applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text); goto out; } res_val = json_object_get(val, "result"); err_val = json_object_get(val, "error"); if (!res_val || json_is_null(res_val) || (err_val && !json_is_null(err_val))) { if (opt_debug || retry) { free(s); if (err_val) s = json_dumps(err_val, JSON_INDENT(3)); else s = strdup("(unknown reason)"); applog(LOG_ERR, "JSON-RPC call failed: %s", s); } goto out; } sid = get_stratum_session_id(res_val); if (opt_debug && !sid) applog(LOG_DEBUG, "Failed to get Stratum session id"); xnonce1 = json_string_value(json_array_get(res_val, 1)); if (!xnonce1) { applog(LOG_ERR, "Failed to get extranonce1"); goto out; } xn2_size = json_integer_value(json_array_get(res_val, 2)); if (!xn2_size) { applog(LOG_ERR, "Failed to get extranonce2_size"); goto out; } pthread_mutex_lock(&sctx->work_lock); free(sctx->session_id); free(sctx->xnonce1); sctx->session_id = sid ? strdup(sid) : NULL; sctx->xnonce1_size = strlen(xnonce1) / 2; sctx->xnonce1 = (unsigned char*)malloc(sctx->xnonce1_size); hex2bin(sctx->xnonce1, xnonce1, sctx->xnonce1_size); sctx->xnonce2_size = xn2_size; sctx->next_diff = 1.0; pthread_mutex_unlock(&sctx->work_lock); if (opt_debug && sid) applog(LOG_DEBUG, "Stratum session id: %s", sctx->session_id); ret = true; out: free(s); if (val) json_decref(val); if (!ret) { if (sret && !retry) { retry = true; goto start; } } return ret; }
bool stratum_socket_full(struct stratum_ctx *sctx, int timeout) { return strlen(sctx->sockbuf) || socket_full(sctx->sock, timeout); }