|
|
|
@ -759,64 +759,6 @@ static void submit_share(proxy_instance_t *proxi, json_t *val)
|
|
|
|
|
mutex_unlock(&proxi->psend_lock); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int proxy_loop(proc_instance_t *pi, proxy_instance_t *proxi) |
|
|
|
|
{ |
|
|
|
|
unixsock_t *us = &pi->us; |
|
|
|
|
ckpool_t *ckp = pi->ckp; |
|
|
|
|
int sockd, ret = 0; |
|
|
|
|
char *buf = NULL; |
|
|
|
|
|
|
|
|
|
/* We're not subscribed and authorised so tell the stratifier to
|
|
|
|
|
* retrieve the first subscription. */ |
|
|
|
|
send_proc(ckp->stratifier, "subscribe"); |
|
|
|
|
send_proc(ckp->stratifier, "notify"); |
|
|
|
|
proxi->notified = false; |
|
|
|
|
|
|
|
|
|
retry: |
|
|
|
|
sockd = accept(us->sockd, NULL, NULL); |
|
|
|
|
if (sockd < 0) { |
|
|
|
|
if (interrupted()) |
|
|
|
|
goto retry; |
|
|
|
|
LOGERR("Failed to accept on proxy socket"); |
|
|
|
|
ret = 1; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
dealloc(buf); |
|
|
|
|
buf = recv_unix_msg(sockd); |
|
|
|
|
if (!buf) { |
|
|
|
|
LOGWARNING("Failed to get message in proxy_loop"); |
|
|
|
|
close(sockd); |
|
|
|
|
goto retry; |
|
|
|
|
} |
|
|
|
|
LOGDEBUG("Proxy received request: %s", buf); |
|
|
|
|
if (!strncasecmp(buf, "shutdown", 8)) { |
|
|
|
|
ret = 0; |
|
|
|
|
goto out; |
|
|
|
|
} else if (!strncasecmp(buf, "getsubscribe", 12)) { |
|
|
|
|
send_subscribe(proxi, sockd); |
|
|
|
|
} else if (!strncasecmp(buf, "getnotify", 9)) { |
|
|
|
|
send_notify(proxi, sockd); |
|
|
|
|
} else if (!strncasecmp(buf, "getdiff", 7)) { |
|
|
|
|
send_diff(proxi, sockd); |
|
|
|
|
} else if (!strncasecmp(buf, "ping", 4)) { |
|
|
|
|
LOGDEBUG("Proxy received ping request"); |
|
|
|
|
send_unix_msg(sockd, "pong"); |
|
|
|
|
} else { |
|
|
|
|
/* Anything remaining should be share submissions */ |
|
|
|
|
json_t *val = json_loads(buf, 0, NULL); |
|
|
|
|
|
|
|
|
|
if (!val) |
|
|
|
|
LOGWARNING("Received unrecognised message: %s", buf); |
|
|
|
|
else |
|
|
|
|
submit_share(proxi, val); |
|
|
|
|
} |
|
|
|
|
close(sockd); |
|
|
|
|
goto retry; |
|
|
|
|
out: |
|
|
|
|
close(sockd); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void clear_notify(notify_instance_t *ni) |
|
|
|
|
{ |
|
|
|
|
free(ni->jobid); |
|
|
|
@ -825,35 +767,8 @@ static void clear_notify(notify_instance_t *ni)
|
|
|
|
|
free(ni); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void reconnect_stratum(connsock_t *cs, proxy_instance_t *proxi) |
|
|
|
|
{ |
|
|
|
|
notify_instance_t *ni, *tmp; |
|
|
|
|
bool ret = true; |
|
|
|
|
|
|
|
|
|
/* All our notify data is invalid if we reconnect so discard them */ |
|
|
|
|
mutex_lock(&proxi->notify_lock); |
|
|
|
|
HASH_ITER(hh, proxi->notify_instances, ni, tmp) { |
|
|
|
|
HASH_DEL(proxi->notify_instances, ni); |
|
|
|
|
clear_notify(ni); |
|
|
|
|
} |
|
|
|
|
mutex_unlock(&proxi->notify_lock); |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
if (!ret) |
|
|
|
|
sleep(5); |
|
|
|
|
close(cs->fd); |
|
|
|
|
ret = connect_proxy(cs); |
|
|
|
|
if (!ret) |
|
|
|
|
continue; |
|
|
|
|
ret = subscribe_stratum(cs, proxi); |
|
|
|
|
if (!ret) |
|
|
|
|
continue; |
|
|
|
|
ret = auth_stratum(cs, proxi); |
|
|
|
|
} while (!ret); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* FIXME: Return something useful to the stratifier based on this result */ |
|
|
|
|
static bool parse_share(ckpool_t *ckp, proxy_instance_t *proxi, const char *buf) |
|
|
|
|
static bool parse_share(proxy_instance_t *proxi, const char *buf) |
|
|
|
|
{ |
|
|
|
|
json_t *val = NULL, *idval; |
|
|
|
|
share_msg_t *share; |
|
|
|
@ -899,6 +814,9 @@ static void *proxy_recv(void *arg)
|
|
|
|
|
ckpool_t *ckp = proxi->ckp; |
|
|
|
|
|
|
|
|
|
rename_proc("proxyrecv"); |
|
|
|
|
/* We don't wait for them to pthread_join in case it takes a while, so
|
|
|
|
|
* we detach the threads instead to clean up themselves */ |
|
|
|
|
pthread_detach(pthread_self()); |
|
|
|
|
|
|
|
|
|
while (42) { |
|
|
|
|
notify_instance_t *ni, *tmp; |
|
|
|
@ -940,11 +858,10 @@ static void *proxy_recv(void *arg)
|
|
|
|
|
} while (ret == 0 && ++retries < 24); |
|
|
|
|
|
|
|
|
|
if (ret < 1) { |
|
|
|
|
/* Send ourselves a reconnect message */ |
|
|
|
|
LOGWARNING("Failed to read_socket_line in proxy_recv, attempting reconnect"); |
|
|
|
|
reconnect_stratum(cs, proxi); |
|
|
|
|
send_proc(ckp->stratifier, "subscribe"); |
|
|
|
|
send_proc(ckp->stratifier, "notify"); |
|
|
|
|
continue; |
|
|
|
|
send_proc(ckp->generator, "reconnect"); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (parse_method(proxi, cs->buf)) { |
|
|
|
|
if (proxi->notified) { |
|
|
|
@ -957,7 +874,7 @@ static void *proxy_recv(void *arg)
|
|
|
|
|
} |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (parse_share(ckp, proxi, cs->buf)) { |
|
|
|
|
if (parse_share(proxi, cs->buf)) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
/* If it's not a method it should be a share result */ |
|
|
|
@ -973,6 +890,7 @@ static void *proxy_send(void *arg)
|
|
|
|
|
connsock_t *cs = proxi->cs; |
|
|
|
|
|
|
|
|
|
rename_proc("proxysend"); |
|
|
|
|
pthread_detach(pthread_self()); |
|
|
|
|
|
|
|
|
|
while (42) { |
|
|
|
|
notify_instance_t *ni; |
|
|
|
@ -1024,61 +942,144 @@ static void *proxy_send(void *arg)
|
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
static int proxy_mode(ckpool_t *ckp, proc_instance_t *pi, connsock_t *cs, |
|
|
|
|
const char *auth, const char *pass) |
|
|
|
|
/* Cycle through the available proxies and find the first alive one */ |
|
|
|
|
static proxy_instance_t *live_proxy(ckpool_t *ckp) |
|
|
|
|
{ |
|
|
|
|
proxy_instance_t proxi; |
|
|
|
|
int ret = 1; |
|
|
|
|
proxy_instance_t *alive = NULL; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
memset(&proxi, 0, sizeof(proxi)); |
|
|
|
|
proxi.ckp = ckp; |
|
|
|
|
proxi.cs = cs; |
|
|
|
|
LOGDEBUG("Attempting to connect to proxy"); |
|
|
|
|
retry: |
|
|
|
|
for (i = 0; i < ckp->proxies; i++) { |
|
|
|
|
proxy_instance_t *proxi; |
|
|
|
|
server_instance_t *si; |
|
|
|
|
connsock_t *cs; |
|
|
|
|
|
|
|
|
|
if (!connect_proxy(cs)) { |
|
|
|
|
LOGWARNING("FATAL: Failed to connect to %s:%s in proxy_mode!", |
|
|
|
|
cs->url, cs->port); |
|
|
|
|
goto out; |
|
|
|
|
si = ckp->servers[i]; |
|
|
|
|
proxi = si->data; |
|
|
|
|
cs = proxi->cs; |
|
|
|
|
if (!extract_sockaddr(si->url, &cs->url, &cs->port)) { |
|
|
|
|
LOGWARNING("Failed to extract address from %s", si->url); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (!connect_proxy(cs)) { |
|
|
|
|
LOGINFO("Failed to connect to %s:%s in proxy_mode!", |
|
|
|
|
cs->url, cs->port); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
/* Test we can connect, authorise and get stratum information */ |
|
|
|
|
if (!subscribe_stratum(cs, proxi)) { |
|
|
|
|
LOGINFO("Failed initial subscribe to %s:%s !", |
|
|
|
|
cs->url, cs->port); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (!auth_stratum(cs, proxi)) { |
|
|
|
|
LOGWARNING("Failed initial authorise to %s:%s with %s:%s !", |
|
|
|
|
cs->url, cs->port, si->auth, si->pass); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
alive = proxi; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Test we can connect, authorise and get stratum information */ |
|
|
|
|
if (!subscribe_stratum(cs, &proxi)) { |
|
|
|
|
LOGWARNING("FATAL: Failed initial subscribe to %s:%s !", |
|
|
|
|
cs->url, cs->port); |
|
|
|
|
goto out; |
|
|
|
|
if (!alive) { |
|
|
|
|
LOGWARNING("Failed to connect to any servers as proxy, retrying in 5s!"); |
|
|
|
|
sleep(5); |
|
|
|
|
goto retry; |
|
|
|
|
} |
|
|
|
|
LOGNOTICE("Connected to upstream server %s:%s as proxy", alive->cs->url, alive->cs->port); |
|
|
|
|
mutex_init(&alive->notify_lock); |
|
|
|
|
create_pthread(&alive->pth_precv, proxy_recv, alive); |
|
|
|
|
mutex_init(&alive->psend_lock); |
|
|
|
|
cond_init(&alive->psend_cond); |
|
|
|
|
create_pthread(&alive->pth_psend, proxy_send, alive); |
|
|
|
|
return alive; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
proxi.auth = auth; |
|
|
|
|
proxi.pass = pass; |
|
|
|
|
if (!auth_stratum(cs, &proxi)) { |
|
|
|
|
LOGWARNING("FATAL: Failed initial authorise to %s:%s with %s:%s !", |
|
|
|
|
cs->url, cs->port, auth, pass); |
|
|
|
|
goto out; |
|
|
|
|
static void kill_proxy(proxy_instance_t *proxi) |
|
|
|
|
{ |
|
|
|
|
notify_instance_t *ni, *tmp; |
|
|
|
|
connsock_t *cs = proxi->cs; |
|
|
|
|
|
|
|
|
|
close(cs->fd); |
|
|
|
|
|
|
|
|
|
/* All our notify data is invalid if we reconnect so discard them */ |
|
|
|
|
mutex_lock(&proxi->notify_lock); |
|
|
|
|
HASH_ITER(hh, proxi->notify_instances, ni, tmp) { |
|
|
|
|
HASH_DEL(proxi->notify_instances, ni); |
|
|
|
|
clear_notify(ni); |
|
|
|
|
} |
|
|
|
|
mutex_unlock(&proxi->notify_lock); |
|
|
|
|
|
|
|
|
|
mutex_init(&proxi.notify_lock); |
|
|
|
|
create_pthread(&proxi.pth_precv, proxy_recv, &proxi); |
|
|
|
|
mutex_init(&proxi.psend_lock); |
|
|
|
|
cond_init(&proxi.psend_cond); |
|
|
|
|
create_pthread(&proxi.pth_psend, proxy_send, &proxi); |
|
|
|
|
pthread_cancel(proxi->pth_precv); |
|
|
|
|
pthread_cancel(proxi->pth_psend); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret = proxy_loop(pi, &proxi); |
|
|
|
|
static int proxy_loop(proc_instance_t *pi) |
|
|
|
|
{ |
|
|
|
|
unixsock_t *us = &pi->us; |
|
|
|
|
ckpool_t *ckp = pi->ckp; |
|
|
|
|
proxy_instance_t *proxi; |
|
|
|
|
int sockd, ret = 0; |
|
|
|
|
char *buf = NULL; |
|
|
|
|
|
|
|
|
|
/* Return from the proxy loop means we have received a shutdown
|
|
|
|
|
* request */ |
|
|
|
|
pthread_cancel(proxi.pth_precv); |
|
|
|
|
pthread_cancel(proxi.pth_psend); |
|
|
|
|
join_pthread(proxi.pth_precv); |
|
|
|
|
join_pthread(proxi.pth_psend); |
|
|
|
|
out: |
|
|
|
|
close(cs->fd); |
|
|
|
|
free(proxi.enonce1); |
|
|
|
|
free(proxi.enonce1bin); |
|
|
|
|
free(proxi.sessionid); |
|
|
|
|
reconnect: |
|
|
|
|
proxi = live_proxy(ckp); |
|
|
|
|
/* We've just subscribed and authorised so tell the stratifier to
|
|
|
|
|
* retrieve the first subscription. */ |
|
|
|
|
send_proc(ckp->stratifier, "subscribe"); |
|
|
|
|
send_proc(ckp->stratifier, "notify"); |
|
|
|
|
proxi->notified = false; |
|
|
|
|
|
|
|
|
|
retry: |
|
|
|
|
sockd = accept(us->sockd, NULL, NULL); |
|
|
|
|
if (sockd < 0) { |
|
|
|
|
if (interrupted()) |
|
|
|
|
goto retry; |
|
|
|
|
LOGERR("Failed to accept on proxy socket"); |
|
|
|
|
ret = 1; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
dealloc(buf); |
|
|
|
|
buf = recv_unix_msg(sockd); |
|
|
|
|
if (!buf) { |
|
|
|
|
LOGWARNING("Failed to get message in proxy_loop"); |
|
|
|
|
close(sockd); |
|
|
|
|
goto retry; |
|
|
|
|
} |
|
|
|
|
LOGDEBUG("Proxy received request: %s", buf); |
|
|
|
|
if (!strncasecmp(buf, "shutdown", 8)) { |
|
|
|
|
ret = 0; |
|
|
|
|
goto out; |
|
|
|
|
} else if (!strncasecmp(buf, "getsubscribe", 12)) { |
|
|
|
|
send_subscribe(proxi, sockd); |
|
|
|
|
} else if (!strncasecmp(buf, "getnotify", 9)) { |
|
|
|
|
send_notify(proxi, sockd); |
|
|
|
|
} else if (!strncasecmp(buf, "getdiff", 7)) { |
|
|
|
|
send_diff(proxi, sockd); |
|
|
|
|
} else if (!strncasecmp(buf, "reconnect", 9)) { |
|
|
|
|
kill_proxy(proxi); |
|
|
|
|
pthread_cancel(proxi->pth_precv); |
|
|
|
|
pthread_cancel(proxi->pth_psend); |
|
|
|
|
goto reconnect; |
|
|
|
|
} else if (!strncasecmp(buf, "ping", 4)) { |
|
|
|
|
LOGDEBUG("Proxy received ping request"); |
|
|
|
|
send_unix_msg(sockd, "pong"); |
|
|
|
|
} else { |
|
|
|
|
/* Anything remaining should be share submissions */ |
|
|
|
|
json_t *val = json_loads(buf, 0, NULL); |
|
|
|
|
|
|
|
|
|
if (!val) |
|
|
|
|
LOGWARNING("Received unrecognised message: %s", buf); |
|
|
|
|
else |
|
|
|
|
submit_share(proxi, val); |
|
|
|
|
} |
|
|
|
|
close(sockd); |
|
|
|
|
goto retry; |
|
|
|
|
out: |
|
|
|
|
kill_proxy(proxi); |
|
|
|
|
close(sockd); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* FIXME: Make these use multiple BTCDs instead of just first alive. */ |
|
|
|
|
static int server_mode(ckpool_t *ckp, proc_instance_t *pi) |
|
|
|
@ -1153,74 +1154,30 @@ out:
|
|
|
|
|
|
|
|
|
|
static int proxy_mode(ckpool_t *ckp, proc_instance_t *pi) |
|
|
|
|
{ |
|
|
|
|
int i, ret = 1, alive = 0; |
|
|
|
|
proxy_instance_t *proxi; |
|
|
|
|
server_instance_t *si; |
|
|
|
|
connsock_t *cs; |
|
|
|
|
int i, ret = 1; |
|
|
|
|
|
|
|
|
|
/* Create all our proxy structures and pointers */ |
|
|
|
|
ckp->servers = ckalloc(sizeof(server_instance_t *) * ckp->proxies); |
|
|
|
|
for (i = 0; i < ckp->proxies; i++) { |
|
|
|
|
|
|
|
|
|
ckp->servers[i] = ckzalloc(sizeof(server_instance_t)); |
|
|
|
|
si = ckp->servers[i]; |
|
|
|
|
cs = &si->cs; |
|
|
|
|
si->url = ckp->proxyurl[i]; |
|
|
|
|
si->auth = ckp->proxyauth[i]; |
|
|
|
|
si->pass = ckp->proxypass[i]; |
|
|
|
|
if (!extract_sockaddr(si->url, &cs->url, &cs->port)) { |
|
|
|
|
LOGWARNING("Failed to extract address from %s", si->url); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (!connect_proxy(cs)) { |
|
|
|
|
LOGWARNING("Failed to connect to %s:%s in proxy_mode!", |
|
|
|
|
cs->url, cs->port); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
proxi = ckzalloc(sizeof(proxy_instance_t)); |
|
|
|
|
si->data = proxi; |
|
|
|
|
/* Test we can connect, authorise and get stratum information */ |
|
|
|
|
if (!subscribe_stratum(cs, proxi)) { |
|
|
|
|
LOGWARNING("Failed initial subscribe to %s:%s !", |
|
|
|
|
cs->url, cs->port); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
proxi->auth = si->auth; |
|
|
|
|
proxi->pass = si->pass; |
|
|
|
|
if (!auth_stratum(cs, proxi)) { |
|
|
|
|
LOGWARNING("Failed initial authorise to %s:%s with %s:%s !", |
|
|
|
|
cs->url, cs->port, si->auth, si->pass); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
proxi->si = si; |
|
|
|
|
proxi->ckp = ckp; |
|
|
|
|
proxi->cs = cs; |
|
|
|
|
si->alive = true; |
|
|
|
|
alive++; |
|
|
|
|
proxi->cs = &si->cs; |
|
|
|
|
} |
|
|
|
|
if (!alive) { |
|
|
|
|
LOGEMERG("FATAL: No proxied servers active!"); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
for (i = 0; i < ckp->proxies; si = ckp->servers[i], i++) { |
|
|
|
|
if (si->alive) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
proxi = si->data; |
|
|
|
|
|
|
|
|
|
mutex_init(&proxi->notify_lock); |
|
|
|
|
create_pthread(&proxi->pth_precv, proxy_recv, proxi); |
|
|
|
|
mutex_init(&proxi->psend_lock); |
|
|
|
|
cond_init(&proxi->psend_cond); |
|
|
|
|
create_pthread(&proxi->pth_psend, proxy_send, proxi); |
|
|
|
|
|
|
|
|
|
ret = proxy_loop(pi, proxi); |
|
|
|
|
ret = proxy_loop(pi); |
|
|
|
|
|
|
|
|
|
/* Return from the proxy loop means we have received a shutdown
|
|
|
|
|
* request */ |
|
|
|
|
pthread_cancel(proxi->pth_precv); |
|
|
|
|
pthread_cancel(proxi->pth_psend); |
|
|
|
|
join_pthread(proxi->pth_precv); |
|
|
|
|
join_pthread(proxi->pth_psend); |
|
|
|
|
out: |
|
|
|
|
for (i = 0; i < ckp->proxies; si = ckp->servers[i], i++) { |
|
|
|
|
close(si->cs.fd); |
|
|
|
|
proxi = si->data; |
|
|
|
|