Browse Source

Move stratum sockets to curl infrastructure with locking around send+recv to begin support for proxies and ssl.

nfactor-troky
Con Kolivas 12 years ago
parent
commit
a8d693029a
  1. 10
      cgminer.c
  2. 3
      configure.ac
  3. 3
      miner.h
  4. 88
      util.c
  5. 2
      util.h

10
cgminer.c

@ -432,6 +432,8 @@ struct pool *add_pool(void)
quit(1, "Failed to pthread_mutex_init in add_pool"); quit(1, "Failed to pthread_mutex_init in add_pool");
if (unlikely(pthread_cond_init(&pool->cr_cond, NULL))) if (unlikely(pthread_cond_init(&pool->cr_cond, NULL)))
quit(1, "Failed to pthread_cond_init in add_pool"); quit(1, "Failed to pthread_cond_init in add_pool");
if (unlikely(pthread_mutex_init(&pool->stratum_lock, NULL)))
quit(1, "Failed to pthread_mutex_init in add_pool");
INIT_LIST_HEAD(&pool->curlring); INIT_LIST_HEAD(&pool->curlring);
/* Make sure the pool doesn't think we've been idle since time 0 */ /* Make sure the pool doesn't think we've been idle since time 0 */
@ -562,12 +564,6 @@ static char *set_rr(enum pool_strategy *strategy)
* stratum+tcp or by detecting a stratum server response */ * stratum+tcp or by detecting a stratum server response */
bool detect_stratum(struct pool *pool, char *url) bool detect_stratum(struct pool *pool, char *url)
{ {
if (pool->rpc_proxy) {
if (!strncasecmp(url, "stratum+tcp://", 14))
applog(LOG_WARNING, "Cannot use a stratum server with a proxy");
return false;
}
if (!extract_sockaddr(pool, url)) if (!extract_sockaddr(pool, url))
return false; return false;
@ -4249,7 +4245,7 @@ retry_stratum:
/* Detect if a http getwork pool has an X-Stratum header at startup, /* Detect if a http getwork pool has an X-Stratum header at startup,
* and if so, switch to that in preference to getwork. Currently no * and if so, switch to that in preference to getwork. Currently no
* proxy support so don't try to switch if a proxy is in use. */ * proxy support so don't try to switch if a proxy is in use. */
if (unlikely(pool->stratum_url && !pool->rpc_proxy)) { if (unlikely(pool->stratum_url)) {
applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url);
pool->has_stratum = true; pool->has_stratum = true;
pool->rpc_url = pool->stratum_url; pool->rpc_url = pool->stratum_url;

3
configure.ac

@ -352,8 +352,7 @@ fi
PKG_PROG_PKG_CONFIG() PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.15.6], [AC_DEFINE([CURL_HAS_SOCKOPT], [1], [Defined if version of curl supports sockopts.])], PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.18.2], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.18.2])])
[PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.10.1], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.10.1])])])
AC_SUBST(LIBCURL_LIBS) AC_SUBST(LIBCURL_LIBS)
dnl CCAN wants to know a lot of vars. dnl CCAN wants to know a lot of vars.

3
miner.h

@ -863,6 +863,8 @@ struct pool {
/* Stratum variables */ /* Stratum variables */
char *stratum_url; char *stratum_url;
char *stratum_port;
CURL *stratum_curl;
SOCKETTYPE sock; SOCKETTYPE sock;
char sockbuf[RBUFSIZE]; char sockbuf[RBUFSIZE];
struct sockaddr_in *server, client; struct sockaddr_in *server, client;
@ -875,6 +877,7 @@ struct pool {
bool stratum_auth; bool stratum_auth;
struct stratum_work swork; struct stratum_work swork;
pthread_t stratum_thread; pthread_t stratum_thread;
pthread_mutex_t stratum_lock;
}; };
#define GETWORK_MODE_TESTPOOL 'T' #define GETWORK_MODE_TESTPOOL 'T'

88
util.c

@ -196,7 +196,6 @@ out:
return ptrlen; return ptrlen;
} }
#ifdef CURL_HAS_SOCKOPT
int json_rpc_call_sockopt_cb(void __maybe_unused *userdata, curl_socket_t fd, int json_rpc_call_sockopt_cb(void __maybe_unused *userdata, curl_socket_t fd,
curlsocktype __maybe_unused purpose) curlsocktype __maybe_unused purpose)
{ {
@ -244,7 +243,6 @@ int json_rpc_call_sockopt_cb(void __maybe_unused *userdata, curl_socket_t fd,
return 0; return 0;
} }
#endif
static void last_nettime(struct timeval *last) static void last_nettime(struct timeval *last)
{ {
@ -319,10 +317,8 @@ json_t *json_rpc_call(CURL *curl, const char *url,
curl_easy_setopt(curl, CURLOPT_USERPWD, userpass); curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
} }
#ifdef CURL_HAS_SOCKOPT
if (longpoll) if (longpoll)
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, json_rpc_call_sockopt_cb); curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, json_rpc_call_sockopt_cb);
#endif
curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_POST, 1);
if (opt_protocol) if (opt_protocol)
@ -835,11 +831,12 @@ bool extract_sockaddr(struct pool *pool, char *url)
sprintf(url_address, "%.*s", url_len, url_begin); sprintf(url_address, "%.*s", url_len, url_begin);
if (port_len) { if (port_len)
sprintf(port, "%.*s", port_len, port_start); sprintf(port, "%.*s", port_len, port_start);
} else { else
strcpy(port, "80"); strcpy(port, "80");
}
pool->stratum_port = strdup(port);
memset(&hints, 0, sizeof(struct addrinfo)); memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@ -859,8 +856,7 @@ bool extract_sockaddr(struct pool *pool, char *url)
/* Send a single command across a socket, appending \n to it */ /* Send a single command across a socket, appending \n to it */
bool stratum_send(struct pool *pool, char *s, ssize_t len) bool stratum_send(struct pool *pool, char *s, ssize_t len)
{ {
SOCKETTYPE sock = pool->sock; ssize_t ssent = 0;
ssize_t sent = 0;
bool ret = false; bool ret = false;
if (opt_protocol) if (opt_protocol)
@ -869,19 +865,21 @@ bool stratum_send(struct pool *pool, char *s, ssize_t len)
strcat(s, "\n"); strcat(s, "\n");
len++; len++;
mutex_lock(&pool->pool_lock); mutex_lock(&pool->stratum_lock);
while (len > 0 ) { while (len > 0 ) {
sent = send(sock, s + sent, len, 0); size_t sent = 0;
if (SOCKETFAIL(sent)) {
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; ret = false;
goto out_unlock; goto out_unlock;
} }
len -= sent; ssent += sent;
len -= ssent;
} }
ret = true; ret = true;
fsync(sock);
out_unlock: out_unlock:
mutex_unlock(&pool->pool_lock); mutex_unlock(&pool->stratum_lock);
return ret;; return ret;;
} }
@ -922,15 +920,25 @@ static bool sock_full(struct pool *pool, bool wait)
* from the socket and returns that as a malloced char */ * from the socket and returns that as a malloced char */
char *recv_line(struct pool *pool) char *recv_line(struct pool *pool)
{ {
SOCKETTYPE sock = pool->sock;
ssize_t len, buflen; ssize_t len, buflen;
char *tok, *sret = NULL; char *tok, *sret = NULL;
size_t n;
if (!strstr(pool->sockbuf, "\n")) { if (!strstr(pool->sockbuf, "\n")) {
char s[RBUFSIZE]; 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); memset(s, 0, RBUFSIZE);
if (SOCKETFAIL(recv(sock, s, RECVSIZE, 0))) {
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"); applog(LOG_DEBUG, "Failed to recv sock in recv_line");
goto out; goto out;
} }
@ -1202,22 +1210,48 @@ out:
bool initiate_stratum(struct pool *pool) bool initiate_stratum(struct pool *pool)
{ {
json_t *val = NULL, *res_val, *err_val; json_t *val = NULL, *res_val, *err_val;
char curl_err_str[CURL_ERROR_SIZE];
char s[RBUFSIZE], *sret = NULL; char s[RBUFSIZE], *sret = NULL;
CURL *curl = NULL;
json_error_t err; json_error_t err;
bool ret = false; bool ret = false;
if (pool->stratum_active) if (pool->stratum_active)
return true; return true;
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;
pool->sock = socket(AF_INET, SOCK_STREAM, 0); /* Create a http url for use with curl */
if (pool->sock == INVSOCK) memset(s, 0, RBUFSIZE);
quit(1, "Failed to create pool socket in initiate_stratum"); sprintf(s, "http://%s:%s", pool->sockaddr_url, pool->stratum_port);
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);
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1);
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_ERR, "Stratum connect failed: %s", curl_err_str);
goto out; 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))) { if (!stratum_send(pool, s, strlen(s))) {
applog(LOG_DEBUG, "Failed to send s in initiate_stratum"); applog(LOG_DEBUG, "Failed to send s in initiate_stratum");
@ -1283,8 +1317,12 @@ out:
applog(LOG_DEBUG, "Pool %d confirmed mining.subscribe with extranonce1 %s extran2size %d", applog(LOG_DEBUG, "Pool %d confirmed mining.subscribe with extranonce1 %s extran2size %d",
pool->pool_no, pool->nonce1, pool->n2size); pool->pool_no, pool->nonce1, pool->n2size);
} }
} else } else {
CLOSESOCKET(pool->sock); if (curl) {
curl_easy_cleanup(curl);
pool->stratum_curl = NULL;
}
}
return ret; return ret;
} }

2
util.h

@ -7,7 +7,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#define SOCKETTYPE int #define SOCKETTYPE long
#define SOCKETFAIL(a) ((a) < 0) #define SOCKETFAIL(a) ((a) < 0)
#define INVSOCK -1 #define INVSOCK -1
#define INVINETADDR -1 #define INVINETADDR -1

Loading…
Cancel
Save