pool/stratum/remote.cpp
2015-07-14 09:29:10 +02:00

301 lines
7.3 KiB
C++

#include "stratum.h"
//#define REMOTE_DEBUGLOG_
bool remote_can_mine(YAAMP_REMOTE *remote)
{
if(!remote) return false;
if(remote->deleted) return false;
if(!remote_connected(remote)) return false;
if(!remote->job) return false;
if(remote->status != YAAMP_REMOTE_READY) return false;
if(remote->renter && remote->renter->balance <= 0) return false;
return true;
}
void remote_sort()
{
for(CLI li = g_list_remote.first; li && li->next; li = li->next)
{
YAAMP_REMOTE *remote1 = (YAAMP_REMOTE *)li->data;
YAAMP_REMOTE *remote2 = (YAAMP_REMOTE *)li->next->data;
if(remote2->price > remote1->price)
{
g_list_remote.Swap(li, li->next);
remote_sort();
return;
}
}
}
bool remote_connected(YAAMP_REMOTE *remote)
{
if(!remote->sock) return false;
return socket_connected(remote->sock);
}
void remote_close(YAAMP_REMOTE *remote)
{
#ifdef REMOTE_DEBUGLOG_
debuglog("remote_close JOB%d\n", remote->id);
#endif
remote->difficulty_actual = 0;
if(remote->status != YAAMP_REMOTE_TERMINATE)
remote->status = YAAMP_REMOTE_CLOSED;
object_delete(remote->job);
remote->job = NULL;
socket_close(remote->sock);
remote->sock = NULL;
}
bool remote_connect(YAAMP_REMOTE *remote)
{
// if(!strcmp(remote->host, "yaamp.com")) return false;
// if(!strcmp(remote->host, "localhost")) return false;
// if(client_find_my_ip(remote->host)) return false;
if(remote_connected(remote))
remote_close(remote);
#ifdef REMOTE_DEBUGLOG_
debuglog("connecting to %s:%d JOB%d\n", remote->host, remote->port, remote->id);
#endif
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock <= 0) return false;
struct hostent *ent = gethostbyname(remote->host);
if(!ent) return false;
struct sockaddr_in serv;
serv.sin_family = AF_INET;
serv.sin_port = htons(remote->port);
bcopy((char *)ent->h_addr, (char *)&serv.sin_addr.s_addr, ent->h_length);
int res = connect(sock, (struct sockaddr*)&serv, sizeof(serv));
if(res < 0)
{
#ifdef REMOTE_DEBUGLOG_
debuglog("cant connect to %s:%d JOB%d\n", remote->host, remote->port, remote->id);
#endif
return false;
}
// int flags = fcntl(sock, F_GETFL, 0);
// fcntl(sock, F_SETFL, flags|O_NONBLOCK);
remote->status = YAAMP_REMOTE_SUBSCRIBE;
remote->sock = socket_initialize(sock);
// remote->updated = time(NULL);
debuglog("connected to %s:%d JOB%d\n", remote->host, remote->port, remote->id);
return true;
}
////////////////////////////////////////////////////////////////////////////
void *remote_thread(void *p)
{
YAAMP_REMOTE *remote = (YAAMP_REMOTE *)p;
const char message_subscribe[] = "{\"id\":1,\"method\":\"mining.subscribe\",\"params\":[\"stratum-proxy/0.0.2\"]}\n";
const char message_extranonce[] = "{\"id\":3,\"method\":\"mining.extranonce.subscribe\",\"params\":[]}\n";
remote_connect(remote);
while(remote->status != YAAMP_REMOTE_TERMINATE)
{
if(!remote_connected(remote))
{
debuglog("disconnected from %s:%d JOB%d\n", remote->host, remote->port, remote->id);
sleep(300);
if(remote->status == YAAMP_REMOTE_TERMINATE) break;
remote_connect(remote);
continue;
}
if(remote->status == YAAMP_REMOTE_TERMINATE)
break;
else if(remote->status == YAAMP_REMOTE_RESET)
{
remote_close(remote);
job_signal();
remote_connect(remote);
continue;
}
else if(remote->status == YAAMP_REMOTE_SUBSCRIBE)
socket_send(remote->sock, message_subscribe);
else if(remote->status == YAAMP_REMOTE_AUTHORIZE)
{
char message_authorize[2*1024];
sprintf(message_authorize, "{\"id\":2,\"method\":\"mining.authorize\",\"params\":[\"%s\",\"%s\"]}\n",
remote->username, remote->password);
socket_send(remote->sock, message_authorize);
}
else if(remote->status == YAAMP_REMOTE_EXTRANONCE)
{
socket_send(remote->sock, message_extranonce);
remote->status = YAAMP_REMOTE_READY;
}
////////////////////////////////////////////////////////////////
json_value *json = socket_nextjson(remote->sock);
if(!json)
{
sleep(1);
remote_close(remote);
job_signal();
continue;
}
if(remote->status == YAAMP_REMOTE_TERMINATE)
{
json_value_free(json);
break;
}
int id = json_get_int(json, "id");
const char *method = json_get_string(json, "method");
json_value *json_params = json_get_array(json, "params");
json_value *json_result = json_get_array(json, "result");
if(id == 1)
{
remote->status = YAAMP_REMOTE_AUTHORIZE;
strncpy(remote->nonce1_next, json_result->u.array.values[1]->u.string.ptr, 16);
remote->nonce2size_next = json_result->u.array.values[2]->u.integer;
if(remote->nonce2size_next < 2)
{
debuglog("error nonce2 too small %d\n", remote->nonce2size_next);
remote_close(remote);
}
}
else if(id == 2)
{
if(remote->status == YAAMP_REMOTE_AUTHORIZE)
remote->status = YAAMP_REMOTE_EXTRANONCE;
}
else if(id == 4)
{
if(json_result && !json_result->u.boolean)
{
if(remote->submit_last) remote->submit_last->valid = false;
// json_value *json_error = json_get_array(json, "error");
// if(json_error && json_error->type == json_array && json_error->u.array.length > 1)
// {
// debuglog("remote submit error JOB%d %d %s ***\n", remote->id,
// (int)json_error->u.array.values[0]->u.integer, json_error->u.array.values[1]->u.string.ptr);
// }
}
}
else if(method)
{
// debuglog(" * remote method %s\n", method);
if(!strcmp(method, "mining.set_difficulty"))
{
if(json_params->u.array.values[0]->type == json_double)
remote->difficulty_next = json_params->u.array.values[0]->u.dbl;
else if(json_params->u.array.values[0]->type == json_integer)
remote->difficulty_next = json_params->u.array.values[0]->u.integer;
else if(json_params->u.array.values[0]->type == json_string)
remote->difficulty_next = atof(json_params->u.array.values[0]->u.string.ptr);
// debuglog("remote difficulty %f\n", remote->difficulty_next);
}
else if(!strcmp(method, "mining.set_extranonce"))
{
strncpy(remote->nonce1_next, json_params->u.array.values[0]->u.string.ptr, 16);
remote->nonce2size_next = json_params->u.array.values[1]->u.integer;
if(remote->nonce2size_next < 2)
{
debuglog("error nonce2 too small %d\n", remote->nonce2size_next);
remote_close(remote);
job_signal();
}
}
else if(!strcmp(method, "mining.notify"))
{
strncpy(remote->jobid, json_params->u.array.values[0]->u.string.ptr, 16);
string_lower(remote->jobid);
if( strcmp(remote->nonce1, remote->nonce1_next) ||
remote->nonce2size != remote->nonce2size_next ||
remote->difficulty_actual != remote->difficulty_next)
{
strncpy(remote->nonce1, remote->nonce1_next, 16);
string_lower(remote->nonce1);
remote->nonce2size = remote->nonce2size_next;
remote->difficulty_actual = remote->difficulty_next;
remote_create_job(remote, json_params);
if(!remote->job) break;
job_signal();
}
else
{
remote_create_job(remote, json_params);
if(!remote->job) break;
job_assign_locked_clients(remote->job);
job_broadcast(remote->job);
}
}
else if(!strcmp(method, "client.reconnect"))
{
remote_close(remote);
job_signal();
remote_connect(remote);
}
}
json_value_free(json);
}
debuglog("terminate JOB%d %s:%d\n", remote->id, remote->host, remote->port);
object_delete(remote);
job_signal();
pthread_exit(NULL);
}