|
|
@@ -216,7 +216,6 @@ out:
|
|
|
return ptrlen;
|
|
|
}
|
|
|
|
|
|
-#ifdef CURL_HAS_SOCKOPT
|
|
|
int json_rpc_call_sockopt_cb(void __maybe_unused *userdata, curl_socket_t fd,
|
|
|
curlsocktype __maybe_unused purpose)
|
|
|
{
|
|
|
@@ -264,7 +263,6 @@ int json_rpc_call_sockopt_cb(void __maybe_unused *userdata, curl_socket_t fd,
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
static void last_nettime(struct timeval *last)
|
|
|
{
|
|
|
@@ -341,10 +339,8 @@ json_t *json_rpc_call(CURL *curl, const char *url,
|
|
|
curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
|
|
|
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
|
|
}
|
|
|
-#ifdef CURL_HAS_SOCKOPT
|
|
|
if (longpoll)
|
|
|
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, json_rpc_call_sockopt_cb);
|
|
|
-#endif
|
|
|
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
|
|
|
|
|
if (opt_protocol)
|
|
|
@@ -789,7 +785,7 @@ double tdiff(struct timeval *end, struct timeval *start)
|
|
|
bool extract_sockaddr(struct pool *pool, char *url)
|
|
|
{
|
|
|
char *url_begin, *url_end, *port_start = NULL;
|
|
|
- char *url_address, *port;
|
|
|
+ char url_address[256], port[6];
|
|
|
struct addrinfo hints, *res;
|
|
|
int url_len, port_len = 0;
|
|
|
|
|
|
@@ -811,16 +807,14 @@ bool extract_sockaddr(struct pool *pool, char *url)
|
|
|
if (url_len < 1)
|
|
|
return false;
|
|
|
|
|
|
- url_address = alloca(url_len + 1);
|
|
|
sprintf(url_address, "%.*s", url_len, url_begin);
|
|
|
|
|
|
- if (port_len) {
|
|
|
- port = alloca(port_len + 1);
|
|
|
+ if (port_len)
|
|
|
sprintf(port, "%.*s", port_len, port_start);
|
|
|
- } else {
|
|
|
- port = alloca(4);
|
|
|
+ else
|
|
|
strcpy(port, "80");
|
|
|
- }
|
|
|
+
|
|
|
+ pool->stratum_port = strdup(port);
|
|
|
|
|
|
memset(&hints, 0, sizeof(struct addrinfo));
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
@@ -840,8 +834,7 @@ bool extract_sockaddr(struct pool *pool, char *url)
|
|
|
/* Send a single command across a socket, appending \n to it */
|
|
|
bool stratum_send(struct pool *pool, char *s, ssize_t len)
|
|
|
{
|
|
|
- SOCKETTYPE sock = pool->sock;
|
|
|
- ssize_t sent = 0;
|
|
|
+ ssize_t ssent = 0;
|
|
|
bool ret = false;
|
|
|
|
|
|
if (opt_protocol)
|
|
|
@@ -850,37 +843,45 @@ bool stratum_send(struct pool *pool, char *s, ssize_t len)
|
|
|
strcat(s, "\n");
|
|
|
len++;
|
|
|
|
|
|
- mutex_lock(&pool->pool_lock);
|
|
|
+ mutex_lock(&pool->stratum_lock);
|
|
|
while (len > 0 ) {
|
|
|
- sent = send(sock, s + sent, len, 0);
|
|
|
- if (SOCKETFAIL(sent)) {
|
|
|
+ size_t sent = 0;
|
|
|
+
|
|
|
+ if (curl_easy_send(pool->stratum_curl, s + ssent, len, &sent) != CURLE_OK) {
|
|
|
+ applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send");
|
|
|
ret = false;
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
- len -= sent;
|
|
|
+ ssent += sent;
|
|
|
+ len -= ssent;
|
|
|
}
|
|
|
ret = true;
|
|
|
- fsync(sock);
|
|
|
out_unlock:
|
|
|
- mutex_unlock(&pool->pool_lock);
|
|
|
+ mutex_unlock(&pool->stratum_lock);
|
|
|
return ret;;
|
|
|
}
|
|
|
|
|
|
#define RECVSIZE 8191
|
|
|
+#define RBUFSIZE (RECVSIZE + 1)
|
|
|
|
|
|
-static void clear_sock(SOCKETTYPE sock)
|
|
|
+static void clear_sock(struct pool *pool)
|
|
|
{
|
|
|
- char *s = alloca(RECVSIZE);
|
|
|
+ SOCKETTYPE sock = pool->sock;
|
|
|
|
|
|
- recv(sock, s, RECVSIZE, MSG_DONTWAIT);
|
|
|
+ recv(sock, pool->sockbuf, RECVSIZE, MSG_DONTWAIT);
|
|
|
+ strcpy(pool->sockbuf, "");
|
|
|
}
|
|
|
|
|
|
/* Check to see if Santa's been good to you */
|
|
|
-static bool sock_full(SOCKETTYPE sock, bool wait)
|
|
|
+static bool sock_full(struct pool *pool, bool wait)
|
|
|
{
|
|
|
+ SOCKETTYPE sock = pool->sock;
|
|
|
struct timeval timeout;
|
|
|
fd_set rd;
|
|
|
|
|
|
+ if (strlen(pool->sockbuf))
|
|
|
+ return true;
|
|
|
+
|
|
|
FD_ZERO(&rd);
|
|
|
FD_SET(sock, &rd);
|
|
|
timeout.tv_usec = 0;
|
|
|
@@ -895,31 +896,51 @@ static bool sock_full(SOCKETTYPE sock, bool wait)
|
|
|
|
|
|
/* Peeks at a socket to find the first end of line and then reads just that
|
|
|
* from the socket and returns that as a malloced char */
|
|
|
-char *recv_line(SOCKETTYPE sock)
|
|
|
+char *recv_line(struct pool *pool)
|
|
|
{
|
|
|
- char *sret = NULL, *s, c;
|
|
|
- ssize_t offset = 0;
|
|
|
+ ssize_t len, buflen;
|
|
|
+ char *tok, *sret = NULL;
|
|
|
+ size_t n;
|
|
|
|
|
|
- s = alloca(RECVSIZE + 1);
|
|
|
- if (SOCKETFAIL(recv(sock, s, RECVSIZE, MSG_PEEK))) {
|
|
|
- applog(LOG_DEBUG, "Failed to recv sock in recv_line");
|
|
|
- goto out;
|
|
|
+ if (!strstr(pool->sockbuf, "\n")) {
|
|
|
+ char s[RBUFSIZE];
|
|
|
+ CURLcode rc;
|
|
|
+
|
|
|
+ if (!sock_full(pool, true)) {
|
|
|
+ applog(LOG_DEBUG, "Timed out waiting for data on sock_full");
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ memset(s, 0, RBUFSIZE);
|
|
|
+
|
|
|
+ mutex_lock(&pool->stratum_lock);
|
|
|
+ rc = curl_easy_recv(pool->stratum_curl, s, RECVSIZE, &n);
|
|
|
+ mutex_unlock(&pool->stratum_lock);
|
|
|
+
|
|
|
+ if (rc != CURLE_OK) {
|
|
|
+ applog(LOG_DEBUG, "Failed to recv sock in recv_line");
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ strcat(pool->sockbuf, s);
|
|
|
}
|
|
|
- sret = strtok(s, "\n");
|
|
|
- if (!sret) {
|
|
|
+
|
|
|
+ buflen = strlen(pool->sockbuf);
|
|
|
+ tok = strtok(pool->sockbuf, "\n");
|
|
|
+ if (!tok) {
|
|
|
applog(LOG_DEBUG, "Failed to parse a \\n terminated string in recv_line");
|
|
|
goto out;
|
|
|
}
|
|
|
+ sret = strdup(tok);
|
|
|
+ len = strlen(sret);
|
|
|
|
|
|
- do {
|
|
|
- read(sock, &c, 1);
|
|
|
- memcpy(s + offset++, &c, 1);
|
|
|
- } while (strncmp(&c, "\n", 1));
|
|
|
- sret = strdup(s);
|
|
|
- strcpy(sret + offset - 1, "\0");
|
|
|
+ /* Copy what's left in the buffer after the \n, including the
|
|
|
+ * terminating \0 */
|
|
|
+ if (buflen > len + 1)
|
|
|
+ memmove(pool->sockbuf, pool->sockbuf + len + 1, buflen - len + 1);
|
|
|
+ else
|
|
|
+ strcpy(pool->sockbuf, "");
|
|
|
out:
|
|
|
if (!sret)
|
|
|
- clear_sock(sock);
|
|
|
+ clear_sock(pool);
|
|
|
else if (opt_protocol)
|
|
|
applog(LOG_DEBUG, "RECVD: %s", sret);
|
|
|
return sret;
|
|
|
@@ -1111,19 +1132,18 @@ out:
|
|
|
bool auth_stratum(struct pool *pool)
|
|
|
{
|
|
|
json_t *val = NULL, *res_val, *err_val;
|
|
|
- char *s, *sret = NULL;
|
|
|
+ char s[RBUFSIZE], *sret = NULL;
|
|
|
json_error_t err;
|
|
|
bool ret = false;
|
|
|
|
|
|
- s = alloca(RECVSIZE + 1);
|
|
|
sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}",
|
|
|
swork_id++, pool->rpc_user, pool->rpc_pass);
|
|
|
|
|
|
/* Parse all data prior sending auth request */
|
|
|
- while (sock_full(pool->sock, false)) {
|
|
|
- sret = recv_line(pool->sock);
|
|
|
+ while (sock_full(pool, false)) {
|
|
|
+ sret = recv_line(pool);
|
|
|
if (!parse_method(pool, sret)) {
|
|
|
- clear_sock(pool->sock);
|
|
|
+ clear_sock(pool);
|
|
|
applog(LOG_WARNING, "Failed to parse stratum buffer");
|
|
|
free(sret);
|
|
|
return ret;
|
|
|
@@ -1134,7 +1154,7 @@ bool auth_stratum(struct pool *pool)
|
|
|
if (!stratum_send(pool, s, strlen(s)))
|
|
|
goto out;
|
|
|
|
|
|
- sret = recv_line(pool->sock);
|
|
|
+ sret = recv_line(pool);
|
|
|
if (!sret)
|
|
|
goto out;
|
|
|
val = JSON_LOADS(sret, &err);
|
|
|
@@ -1168,35 +1188,59 @@ out:
|
|
|
bool initiate_stratum(struct pool *pool)
|
|
|
{
|
|
|
json_t *val = NULL, *res_val, *err_val;
|
|
|
- char *s, *sret = NULL;
|
|
|
+ char curl_err_str[CURL_ERROR_SIZE];
|
|
|
+ char s[RBUFSIZE], *sret = NULL;
|
|
|
+ CURL *curl = NULL;
|
|
|
json_error_t err;
|
|
|
bool ret = false;
|
|
|
|
|
|
if (pool->stratum_active)
|
|
|
return true;
|
|
|
|
|
|
- s = alloca(RECVSIZE + 1);
|
|
|
- sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++);
|
|
|
+ if (!pool->stratum_curl) {
|
|
|
+ pool->stratum_curl = curl_easy_init();
|
|
|
+ if (unlikely(!pool->stratum_curl))
|
|
|
+ quit(1, "Failed to curl_easy_init in initiate_stratum");
|
|
|
+ }
|
|
|
+ curl = pool->stratum_curl;
|
|
|
+
|
|
|
+ /* Create a http url for use with curl */
|
|
|
+ memset(s, 0, RBUFSIZE);
|
|
|
+ sprintf(s, "http://%s:%s", pool->sockaddr_url, pool->stratum_port);
|
|
|
|
|
|
- pool->sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
- if (pool->sock == INVSOCK)
|
|
|
- quit(1, "Failed to create pool socket in initiate_stratum");
|
|
|
- if (SOCKETFAIL(connect(pool->sock, (struct sockaddr *)pool->server, sizeof(struct sockaddr)))) {
|
|
|
- applog(LOG_DEBUG, "Failed to connect socket to pool");
|
|
|
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_str);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_URL, s);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
|
|
|
+ if (pool->rpc_proxy) {
|
|
|
+ curl_easy_setopt(curl, CURLOPT_PROXY, pool->rpc_proxy);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, pool->rpc_proxytype);
|
|
|
+ } else if (opt_socks_proxy) {
|
|
|
+ curl_easy_setopt(curl, CURLOPT_PROXY, opt_socks_proxy);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
|
|
|
+ }
|
|
|
+ curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1);
|
|
|
+ if (curl_easy_perform(curl)) {
|
|
|
+ applog(LOG_INFO, "Stratum connect failed to pool %d: %s", pool->pool_no, curl_err_str);
|
|
|
goto out;
|
|
|
}
|
|
|
+ curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, (long *)&pool->sock);
|
|
|
+
|
|
|
+ sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++);
|
|
|
|
|
|
if (!stratum_send(pool, s, strlen(s))) {
|
|
|
applog(LOG_DEBUG, "Failed to send s in initiate_stratum");
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (!sock_full(pool->sock, true)) {
|
|
|
+ if (!sock_full(pool, true)) {
|
|
|
applog(LOG_DEBUG, "Timed out waiting for response in initiate_stratum");
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- sret = recv_line(pool->sock);
|
|
|
+ sret = recv_line(pool);
|
|
|
if (!sret)
|
|
|
goto out;
|
|
|
|
|
|
@@ -1250,8 +1294,12 @@ out:
|
|
|
applog(LOG_DEBUG, "Pool %d confirmed mining.subscribe with extranonce1 %s extran2size %d",
|
|
|
pool->pool_no, pool->nonce1, pool->n2size);
|
|
|
}
|
|
|
- } else
|
|
|
- CLOSESOCKET(pool->sock);
|
|
|
+ } else {
|
|
|
+ if (curl) {
|
|
|
+ curl_easy_cleanup(curl);
|
|
|
+ pool->stratum_curl = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
return ret;
|
|
|
}
|