mirror of
https://github.com/LBRYFoundation/pool.git
synced 2025-08-23 17:37:25 +00:00
stratum: allow to use curl (optional) for HTTP/1.1 chunks
Todo: SSL RPC connections... user/pw vars may be required... Also, update the make files and handle better the getwork client requests.. Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com>
This commit is contained in:
parent
c615d086b4
commit
a24bf3dd3c
14 changed files with 642 additions and 106 deletions
|
@ -1,7 +1,8 @@
|
|||
|
||||
CC=gcc
|
||||
|
||||
CFLAGS=-c -g `mysql_config --cflags --libs` -march=native
|
||||
CFLAGS= -g -march=native
|
||||
SQLFLAGS= `mysql_config --cflags --libs`
|
||||
|
||||
# Comment this line to disable address check on login,
|
||||
# if you use the auto exchange feature...
|
||||
|
@ -24,6 +25,11 @@ SOURCES=stratum.cpp db.cpp coind.cpp coind_aux.cpp coind_template.cpp coind_subm
|
|||
client.cpp client_submit.cpp client_core.cpp client_difficulty.cpp remote.cpp remote_template.cpp \
|
||||
user.cpp object.cpp json.cpp base58.cpp
|
||||
|
||||
CFLAGS += -DHAVE_CURL
|
||||
SOURCES += rpc_curl.cpp
|
||||
LDCURL = $(shell /usr/bin/pkg-config --static --libs libcurl)
|
||||
LDFLAGS += $(LDCURL)
|
||||
|
||||
OBJECTS=$(SOURCES:.cpp=.o)
|
||||
OUTPUT=stratum
|
||||
|
||||
|
@ -43,13 +49,13 @@ projectcode2:
|
|||
$(SOURCES): stratum.h util.h
|
||||
|
||||
$(OUTPUT): $(OBJECTS)
|
||||
$(CC) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $@
|
||||
$(CC) $(OBJECTS) $(LDLIBS) $(LDFLAGS) -o $@
|
||||
|
||||
.cpp.o:
|
||||
$(CC) $(CFLAGS) $<
|
||||
$(CC) $(CFLAGS) $(SQLFLAGS) -c $<
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $<
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
|
|
|
@ -4,7 +4,8 @@ CC=gcc
|
|||
#CFLAGS=-c -g -I /usr/include/mysql
|
||||
#LDFLAGS=-g
|
||||
|
||||
CFLAGS=-c -std=gnu99 -O2 -I.. -I/usr/include/mysql -march=native
|
||||
CXXFLAGS = -O2 -I.. -march=native
|
||||
CFLAGS= $(CXXFLAGS) -std=gnu99
|
||||
LDFLAGS=-O2 -lgmp
|
||||
|
||||
SOURCES=lyra2re.c lyra2v2.c Lyra2.c Sponge.c blake.c scrypt.c c11.c x11.c x13.c sha256.c keccak.c \
|
||||
|
@ -25,10 +26,10 @@ $(OUTPUT): $(OBJECTS)
|
|||
ar rc $@ $(OBJECTS)
|
||||
|
||||
.cpp.o:
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
$(CC) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# $(CC) $(CFLAGS) -std=gnu99 -Wno-pointer-sign -Wno-pointer-to-int-cast -funroll-loops -fvariable-expansion-in-unroller -fmerge-all-constants -fbranch-target-load-optimize2 -fsched2-use-superblocks -falign-loops=16 -falign-functions=16 -falign-jumps=16 -falign-labels=16 -Ofast -flto -fuse-linker-plugin -ftree-loop-if-convert-stores -DUSE_ASM -pg $<
|
||||
|
||||
|
|
|
@ -173,11 +173,17 @@ bool client_authorize(YAAMP_CLIENT *client, json_value *json_params)
|
|||
{
|
||||
strncpy(client->username, json_params->u.array.values[0]->u.string.ptr, 1023);
|
||||
|
||||
client->username[34] = 0;
|
||||
strncpy(client->worker, client->username+35, 1023);
|
||||
|
||||
// debuglog("%s\n", client->username);
|
||||
// debuglog("%s\n", client->worker);
|
||||
char sep = client->username[34];
|
||||
if (sep == '.' || sep == ',' || sep == ':') {
|
||||
client->username[34] = 0;
|
||||
strncpy(client->worker, client->username+35, 1023-35);
|
||||
// debuglog("%s\n", client->username);
|
||||
// debuglog("%s\n", client->worker);
|
||||
} else if (strlen(client->username) > 35) {
|
||||
client->username[35] = 0;
|
||||
strncpy(client->worker, client->username+36, 1023-36);
|
||||
debuglog("address %s was too long, truncated to 35 chars\n", client->username);
|
||||
}
|
||||
}
|
||||
|
||||
bool reset = client_initialize_multialgo(client);
|
||||
|
@ -225,7 +231,6 @@ bool client_authorize(YAAMP_CLIENT *client, json_value *json_params)
|
|||
|
||||
if(client->jobid_locked)
|
||||
job_send_jobid(client, client->jobid_locked);
|
||||
|
||||
else
|
||||
job_send_last(client);
|
||||
|
||||
|
|
|
@ -144,16 +144,20 @@ bool coind_validate_address(YAAMP_COIND *coind)
|
|||
|
||||
void coind_init(YAAMP_COIND *coind)
|
||||
{
|
||||
char params[YAAMP_SMALLBUFSIZE];
|
||||
char account[YAAMP_SMALLBUFSIZE] = { 0 };
|
||||
|
||||
yaamp_create_mutex(&coind->mutex);
|
||||
|
||||
char account[YAAMP_SMALLBUFSIZE] = { 0 };
|
||||
coind->rpc.curl = 0;
|
||||
if(!strcmp(coind->symbol, "DCR") || !strcmp(coind->symbol, "DCRD")) {
|
||||
coind->rpc.curl = 1;
|
||||
sprintf(account, "default");
|
||||
}
|
||||
|
||||
bool valid = coind_validate_address(coind);
|
||||
if(valid) return;
|
||||
|
||||
if(!strcmp(coind->symbol, "DCRD"))
|
||||
sprintf(account, "default");
|
||||
|
||||
char params[YAAMP_SMALLBUFSIZE];
|
||||
sprintf(params, "[\"%s\"]", account);
|
||||
|
||||
json_value *json = rpc_call(&coind->rpc, "getaccountaddress", params);
|
||||
|
|
|
@ -95,6 +95,44 @@ YAAMP_JOB_TEMPLATE *coind_create_template_memorypool(YAAMP_COIND *coind)
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int coind_parse_decred_header(YAAMP_JOB_TEMPLATE *templ, json_value *json)
|
||||
{
|
||||
struct __attribute__((__packed__)) {
|
||||
uint32_t version;
|
||||
char prevblock[32];
|
||||
char merkleroot[32];
|
||||
char stakeroot[32];
|
||||
uint16_t votebits;
|
||||
char finalstate[6];
|
||||
uint16_t voters;
|
||||
uint8_t freshstake;
|
||||
uint8_t revoc;
|
||||
uint32_t poolsize;
|
||||
uint32_t nbits;
|
||||
uint64_t sbits;
|
||||
uint32_t height;
|
||||
uint32_t size;
|
||||
uint32_t ntime;
|
||||
uint32_t nonce;
|
||||
char extra[36];
|
||||
} header;
|
||||
|
||||
const char *header_hex = json_get_string(json, "header");
|
||||
if (!header_hex) return -1;
|
||||
|
||||
//debuglog("HEADER: %s\n", header_hex);
|
||||
|
||||
binlify((unsigned char*) &header, header_hex);
|
||||
|
||||
templ->height = header.height;
|
||||
sprintf(templ->version, "%08x", header.version);
|
||||
sprintf(templ->ntime, "%08x", header.ntime);
|
||||
sprintf(templ->nbits, "%08x", header.nbits);
|
||||
hexlify(templ->prevhash_hex, (const unsigned char*) header.prevblock, 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
YAAMP_JOB_TEMPLATE *coind_create_template(YAAMP_COIND *coind)
|
||||
{
|
||||
if(coind->usememorypool)
|
||||
|
@ -150,9 +188,13 @@ YAAMP_JOB_TEMPLATE *coind_create_template(YAAMP_COIND *coind)
|
|||
const char *flags = json_get_string(json_coinbaseaux, "flags");
|
||||
strcpy(templ->flags, flags ? flags : "");
|
||||
|
||||
if (!strcmp(coind->symbol, "DCR") || !strcmp(coind->symbol, "DCRD")) {
|
||||
coind_parse_decred_header(templ, json_result);
|
||||
}
|
||||
else
|
||||
if (!coind->height || !flags || !prev || !bits) {
|
||||
stratumlog("%s incompatible getblocktemplate format : height=%d value=%d bits=%s prev=%s\n",
|
||||
coind->symbol, coind->height, templ->value, bits, prev);
|
||||
stratumlog("%s warning, gbt incorrect : version=%s height=%d value=%d bits=%s prev=%s\n",
|
||||
coind->symbol, templ->version, templ->height, templ->value, templ->nbits, templ->prevhash_hex);
|
||||
}
|
||||
|
||||
// temporary hack, until wallet is fixed...
|
||||
|
|
|
@ -978,3 +978,26 @@ void json_value_free (json_value * value)
|
|||
json_value_free_ex (&settings, value);
|
||||
}
|
||||
|
||||
char* json_dumps(json_value * value, int opt)
|
||||
{
|
||||
return strdup(""); // unsupported
|
||||
}
|
||||
|
||||
int json_integer_value(const json_value *json)
|
||||
{
|
||||
json_int_t n;
|
||||
if(!json_is_integer(json))
|
||||
return 0;
|
||||
|
||||
n = *(json);
|
||||
|
||||
return (int) n;
|
||||
}
|
||||
|
||||
char* json_string_value(const json_value *json)
|
||||
{
|
||||
if(!json_is_string(json))
|
||||
return 0;
|
||||
|
||||
return json->u.string.ptr;
|
||||
}
|
||||
|
|
|
@ -261,6 +261,18 @@ void json_value_free (json_value *);
|
|||
void json_value_free_ex (json_settings * settings,
|
||||
json_value *);
|
||||
|
||||
// todo
|
||||
char* json_dumps(json_value * value, int opt);
|
||||
|
||||
typedef json_value json_t;
|
||||
#define json_typeof(json) ((json)->type)
|
||||
#define json_is_array(json) (json && json_typeof(json) == json_array)
|
||||
#define json_is_integer(json) (json && json_typeof(json) == json_integer)
|
||||
#define json_is_string(json) (json && json_typeof(json) == json_string)
|
||||
#define json_is_null(json) (json && json_typeof(json) == json_null)
|
||||
|
||||
int json_integer_value(const json_value *json);
|
||||
char* json_string_value(const json_value *json);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
|
|
@ -113,65 +113,14 @@ int rpc_send(YAAMP_RPC *rpc, const char *format, ...)
|
|||
return bytes;
|
||||
}
|
||||
|
||||
// Attempt to read decred HTTP 1.1 chunked data... not finished
|
||||
char *rpc_get_chunks(YAAMP_RPC *rpc, char *buffer)
|
||||
{
|
||||
char *val, *databuf = NULL;
|
||||
int datalen, reslen = 0;
|
||||
int respos = 0;
|
||||
|
||||
header_value(buffer, "Connection:", val);
|
||||
bool close = (strcmp(val, "close") == 0);
|
||||
|
||||
const char *p = strstr(buffer, "\r\n\r\n");
|
||||
// read chunk len
|
||||
if (p && sscanf(p+4, "%x", &datalen))
|
||||
{
|
||||
p += 4;
|
||||
reslen += datalen;
|
||||
databuf = (char *)realloc(databuf, reslen + 4);
|
||||
if(!databuf) {
|
||||
debuglog("ERR: %s OOM", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
p = strstr(p, "\r\n");
|
||||
if (p) p += 2;
|
||||
while (datalen && p) {
|
||||
memcpy(databuf + respos, p, datalen);
|
||||
databuf[respos + datalen]='\0';
|
||||
respos += reslen;
|
||||
p = strstr(p+datalen, "\r\n");
|
||||
if (!p || !sscanf(p+2, "%x", &datalen)) break;
|
||||
//debuglog("chunk: len %d\n", datalen);
|
||||
if (!datalen) break;
|
||||
|
||||
reslen += datalen;
|
||||
databuf = (char *)realloc(databuf, reslen + 4);
|
||||
int bytes = recv(rpc->sock, buffer, min(YAAMP_SMALLBUFSIZE, datalen), 0);
|
||||
if (bytes <=0) break;
|
||||
p = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
CommonUnlock(&rpc->mutex);
|
||||
|
||||
if (close) {
|
||||
rpc_connect(rpc);
|
||||
}
|
||||
|
||||
return databuf;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char *rpc_do_call(YAAMP_RPC *rpc, char const *data, int http_ver)
|
||||
char *rpc_do_call(YAAMP_RPC *rpc, char const *data)
|
||||
{
|
||||
CommonLock(&rpc->mutex);
|
||||
|
||||
// HTTP 1.1 accepts chunked data, and keep the connection
|
||||
rpc_send(rpc, "POST / HTTP/1.%d\r\n", http_ver);
|
||||
rpc_send(rpc, "POST / HTTP/1.1\r\n");
|
||||
rpc_send(rpc, "Authorization: Basic %s\r\n", rpc->credential);
|
||||
rpc_send(rpc, "Host: %s:%d\n", rpc->host, rpc->port);
|
||||
rpc_send(rpc, "Accept: */*\r\n");
|
||||
|
@ -230,25 +179,23 @@ char *rpc_do_call(YAAMP_RPC *rpc, char const *data, int http_ver)
|
|||
char tmp[1024];
|
||||
|
||||
header_value(buffer, "Transfer-Encoding:", tmp);
|
||||
if (!strcmp(tmp, "chunked") && http_ver == 1) {
|
||||
//return rpc_get_chunks(rpc, buffer);
|
||||
if (!strcmp(tmp, "chunked")) {
|
||||
#ifdef HAVE_CURL
|
||||
if (!rpc->curl) debuglog("%s chunked transfer detected, switching to curl!\n",
|
||||
rpc->coind->symbol);
|
||||
rpc->curl = 1;
|
||||
#endif
|
||||
CommonUnlock(&rpc->mutex);
|
||||
rpc_connect(rpc);
|
||||
return rpc_do_call(rpc, data, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int datalen = atoi(header_value(buffer, "Content-Length:", tmp));
|
||||
if(!datalen)
|
||||
{
|
||||
if (http_ver == 0) {
|
||||
const char *end = strstr(buffer, "\r\n\r\n");
|
||||
if (end) datalen = strlen(end + 4);
|
||||
}
|
||||
if (!datalen) {
|
||||
debuglog("ERROR: rpc No Content-Length header!\n");
|
||||
CommonUnlock(&rpc->mutex);
|
||||
return NULL;
|
||||
}
|
||||
debuglog("ERROR: rpc No Content-Length header!\n");
|
||||
CommonUnlock(&rpc->mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = strstr(buffer, "\r\n\r\n");
|
||||
|
@ -296,6 +243,11 @@ json_value *rpc_call(YAAMP_RPC *rpc, char const *method, char const *params)
|
|||
{
|
||||
// debuglog("rpc_call :%d %s\n", rpc->port, method);
|
||||
|
||||
#ifdef HAVE_CURL
|
||||
if (rpc->ssl || rpc->curl)
|
||||
return rpc_curl_call(rpc, method, params);
|
||||
#endif
|
||||
|
||||
int s1 = current_timestamp();
|
||||
if(!rpc_connected(rpc)) return NULL;
|
||||
|
||||
|
@ -309,7 +261,7 @@ json_value *rpc_call(YAAMP_RPC *rpc, char const *method, char const *params)
|
|||
else
|
||||
sprintf(message, "{\"method\":\"%s\",\"id\":\"%d\"}", method, ++rpc->id);
|
||||
|
||||
char *buffer = rpc_do_call(rpc, message, 1);
|
||||
char *buffer = rpc_do_call(rpc, message);
|
||||
|
||||
free(message);
|
||||
if(!buffer) return NULL;
|
||||
|
|
|
@ -11,6 +11,7 @@ struct YAAMP_RPC
|
|||
char cert[1024];
|
||||
|
||||
int ssl;
|
||||
int curl;
|
||||
int sock;
|
||||
int id;
|
||||
|
||||
|
@ -32,3 +33,4 @@ int rpc_flush(YAAMP_RPC *rpc);
|
|||
|
||||
json_value *rpc_call(YAAMP_RPC *rpc, char const *method, char const *params=NULL);
|
||||
|
||||
json_value *rpc_curl_call(YAAMP_RPC *rpc, char const *method, char const *params);
|
||||
|
|
484
stratum/rpc_curl.cpp
Normal file
484
stratum/rpc_curl.cpp
Normal file
|
@ -0,0 +1,484 @@
|
|||
|
||||
#include "stratum.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
//#define RPC_DEBUGLOG_
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <mstcpip.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
static __thread CURL *curl = NULL;
|
||||
|
||||
bool opt_timeout = CURL_RPC_TIMEOUT; // 30sec
|
||||
bool opt_debug = false;
|
||||
bool opt_protocol = false;
|
||||
bool opt_proxy = false;
|
||||
long opt_proxy_type = 0; //CURLPROXY_SOCKS5;
|
||||
|
||||
#define USER_AGENT "stratum/yiimp"
|
||||
#define JSON_INDENT(x) 0
|
||||
#define json_object_get(j,k) json_get_object(j,k)
|
||||
|
||||
struct data_buffer {
|
||||
void *buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct upload_buffer {
|
||||
const void *buf;
|
||||
size_t len;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
struct header_info {
|
||||
char *lp_path;
|
||||
char *reason;
|
||||
char *stratum_url;
|
||||
};
|
||||
|
||||
static void databuf_free(struct data_buffer *db)
|
||||
{
|
||||
if (!db)
|
||||
return;
|
||||
|
||||
free(db->buf);
|
||||
|
||||
memset(db, 0, sizeof(*db));
|
||||
}
|
||||
|
||||
static size_t all_data_cb(const void *ptr, size_t size, size_t nmemb,
|
||||
void *user_data)
|
||||
{
|
||||
struct data_buffer *db = (struct data_buffer *)user_data;
|
||||
size_t len = size * nmemb;
|
||||
size_t oldlen, newlen;
|
||||
void *newmem;
|
||||
static const unsigned char zero = 0;
|
||||
|
||||
oldlen = db->len;
|
||||
newlen = oldlen + len;
|
||||
|
||||
newmem = realloc(db->buf, newlen + 1);
|
||||
if (!newmem)
|
||||
return 0;
|
||||
|
||||
db->buf = newmem;
|
||||
db->len = newlen;
|
||||
memcpy((char*)db->buf + oldlen, ptr, len);
|
||||
memcpy((char*)db->buf + newlen, &zero, 1); /* null terminate */
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t upload_data_cb(void *ptr, size_t size, size_t nmemb,
|
||||
void *user_data)
|
||||
{
|
||||
struct upload_buffer *ub = (struct upload_buffer *)user_data;
|
||||
unsigned int len = (unsigned int)(size * nmemb);
|
||||
|
||||
if (len > ub->len - ub->pos)
|
||||
len = (unsigned int)(ub->len - ub->pos);
|
||||
|
||||
if (len) {
|
||||
memcpy(ptr, (char*)ub->buf + ub->pos, len);
|
||||
ub->pos += len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x071200
|
||||
static int seek_data_cb(void *user_data, curl_off_t offset, int origin)
|
||||
{
|
||||
struct upload_buffer *ub = (struct upload_buffer *)user_data;
|
||||
|
||||
switch (origin) {
|
||||
case SEEK_SET:
|
||||
ub->pos = (size_t)offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
ub->pos += (size_t)offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
ub->pos = ub->len + (size_t)offset;
|
||||
break;
|
||||
default:
|
||||
return 1; /* CURL_SEEKFUNC_FAIL */
|
||||
}
|
||||
|
||||
return 0; /* CURL_SEEKFUNC_OK */
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t resp_hdr_cb(void *ptr, size_t size, size_t nmemb, void *user_data)
|
||||
{
|
||||
struct header_info *hi = (struct header_info *)user_data;
|
||||
size_t remlen, slen, ptrlen = size * nmemb;
|
||||
char *rem, *val = NULL, *key = NULL;
|
||||
void *tmp;
|
||||
|
||||
val = (char*)calloc(1, ptrlen);
|
||||
key = (char*)calloc(1, ptrlen);
|
||||
if (!key || !val)
|
||||
goto out;
|
||||
|
||||
tmp = memchr(ptr, ':', ptrlen);
|
||||
if (!tmp || (tmp == ptr)) /* skip empty keys / blanks */
|
||||
goto out;
|
||||
slen = (size_t)((char*)tmp - (char*)ptr);
|
||||
if ((slen + 1) == ptrlen) /* skip key w/ no value */
|
||||
goto out;
|
||||
memcpy(key, ptr, slen); /* store & nul term key */
|
||||
key[slen] = 0;
|
||||
|
||||
rem = (char*)ptr + slen + 1; /* trim value's leading whitespace */
|
||||
remlen = ptrlen - slen - 1;
|
||||
while ((remlen > 0) && (isspace(*rem))) {
|
||||
remlen--;
|
||||
rem++;
|
||||
}
|
||||
|
||||
memcpy(val, rem, remlen); /* store value, trim trailing ws */
|
||||
val[remlen] = 0;
|
||||
while ((*val) && (isspace(val[strlen(val) - 1]))) {
|
||||
val[strlen(val) - 1] = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
free(key);
|
||||
free(val);
|
||||
return ptrlen;
|
||||
}
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x070f06
|
||||
static int sockopt_keepalive_cb(void *userdata, curl_socket_t fd,
|
||||
curlsocktype purpose)
|
||||
{
|
||||
int keepalive = 1;
|
||||
int tcp_keepcnt = 3;
|
||||
int tcp_keepidle = 50;
|
||||
int tcp_keepintvl = 50;
|
||||
#ifdef WIN32
|
||||
DWORD outputBytes;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)))
|
||||
return 1;
|
||||
#ifdef __linux
|
||||
if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &tcp_keepcnt, sizeof(tcp_keepcnt)))
|
||||
return 1;
|
||||
if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle)))
|
||||
return 1;
|
||||
if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl)))
|
||||
return 1;
|
||||
#endif /* __linux */
|
||||
#ifdef __APPLE_CC__
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &tcp_keepintvl, sizeof(tcp_keepintvl)))
|
||||
return 1;
|
||||
#endif /* __APPLE_CC__ */
|
||||
#else /* WIN32 */
|
||||
struct tcp_keepalive vals;
|
||||
vals.onoff = 1;
|
||||
vals.keepalivetime = tcp_keepidle * 1000;
|
||||
vals.keepaliveinterval = tcp_keepintvl * 1000;
|
||||
if (unlikely(WSAIoctl(fd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals),
|
||||
NULL, 0, &outputBytes, NULL, NULL)))
|
||||
return 1;
|
||||
#endif /* WIN32 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static json_value *curl_json_rpc(YAAMP_RPC *rpc, const char *url, const char *rpc_req, int *curl_err)
|
||||
{
|
||||
char len_hdr[64], auth_hdr[64];
|
||||
char curl_err_str[CURL_ERROR_SIZE] = { 0 };
|
||||
struct data_buffer all_data = { 0 };
|
||||
struct upload_buffer upload_data;
|
||||
struct curl_slist *headers = NULL;
|
||||
struct header_info hi = { 0 };
|
||||
char *httpdata;
|
||||
json_value *val, *err_val, *res_val;
|
||||
int rc;
|
||||
|
||||
long timeout = opt_timeout;
|
||||
bool keepalive = false;
|
||||
|
||||
/* it is assumed that 'curl' is freshly [re]initialized at this pt */
|
||||
|
||||
if (opt_protocol)
|
||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
|
||||
if (rpc->ssl) {
|
||||
curl_easy_setopt(curl, CURLOPT_SSLVERSION, 1); // TLSv1
|
||||
if (strlen(rpc->cert))
|
||||
curl_easy_setopt(curl, CURLOPT_CAINFO, rpc->cert);
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_ENCODING, "");
|
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0);
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, all_data_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &all_data);
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, upload_data_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_data);
|
||||
#if LIBCURL_VERSION_NUM >= 0x071200
|
||||
curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, &seek_data_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_SEEKDATA, &upload_data);
|
||||
#endif
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_str);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, resp_hdr_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &hi);
|
||||
if (opt_proxy) {
|
||||
curl_easy_setopt(curl, CURLOPT_PROXY, opt_proxy);
|
||||
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, opt_proxy_type);
|
||||
}
|
||||
|
||||
#if 0
|
||||
curl_easy_setopt(curl, CURLOPT_USERPWD, rpc->credential);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
#else
|
||||
sprintf(auth_hdr, "Authorization: Basic %s", rpc->credential);
|
||||
#endif
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x070f06
|
||||
if (keepalive)
|
||||
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_keepalive_cb);
|
||||
#endif
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
|
||||
if (opt_protocol)
|
||||
debuglog("JSON protocol request:\n%s", rpc_req);
|
||||
|
||||
upload_data.buf = rpc_req;
|
||||
upload_data.len = strlen(rpc_req);
|
||||
upload_data.pos = 0;
|
||||
sprintf(len_hdr, "Content-Length: %lu", (unsigned long) upload_data.len);
|
||||
|
||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||
headers = curl_slist_append(headers, len_hdr);
|
||||
headers = curl_slist_append(headers, auth_hdr);
|
||||
headers = curl_slist_append(headers, "User-Agent: " USER_AGENT);
|
||||
headers = curl_slist_append(headers, "Accept:"); /* disable Accept hdr*/
|
||||
headers = curl_slist_append(headers, "Expect:"); /* disable Expect hdr*/
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
rc = curl_easy_perform(curl);
|
||||
if (curl_err != NULL)
|
||||
*curl_err = rc;
|
||||
if (rc) {
|
||||
if (rc != CURLE_OPERATION_TIMEDOUT) {
|
||||
debuglog("ERR: HTTP request failed: %s", curl_err_str);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!all_data.buf || !all_data.len) {
|
||||
debuglog("ERR: Empty data received in json_rpc_call.");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
httpdata = (char*) all_data.buf;
|
||||
|
||||
if (*httpdata != '{' && *httpdata != '[') {
|
||||
long errcode = 0;
|
||||
CURLcode c = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &errcode);
|
||||
if (c == CURLE_OK && errcode == 401) {
|
||||
debuglog("ERR: You are not authorized, check your login and password.");
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
val = json_parse(httpdata, strlen(httpdata));
|
||||
if (!val) {
|
||||
debuglog("ERR: JSON decode failed!");
|
||||
if (opt_protocol)
|
||||
debuglog("%s", httpdata);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (opt_protocol) {
|
||||
//char *s = json_dumps(val, JSON_INDENT(3));
|
||||
debuglog("JSON protocol response:\n%s\n", httpdata);
|
||||
//free(s);
|
||||
}
|
||||
|
||||
/* JSON-RPC valid response returns a non-null 'result',
|
||||
* and a null 'error'. */
|
||||
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))) {
|
||||
char *s = NULL;
|
||||
|
||||
if (err_val) {
|
||||
s = json_dumps(err_val, 0);
|
||||
json_value *msg = json_object_get(err_val, "message");
|
||||
json_value *err_code = json_object_get(err_val, "code");
|
||||
if (curl_err && json_integer_value(err_code))
|
||||
*curl_err = (int) json_integer_value(err_code);
|
||||
|
||||
if (json_is_string(msg)) {
|
||||
free(s);
|
||||
s = strdup(json_string_value(msg));
|
||||
}
|
||||
//json_decref(err_val);
|
||||
}
|
||||
else
|
||||
s = strdup("(unknown reason)");
|
||||
|
||||
if (!curl_err || opt_debug)
|
||||
debuglog("ERR: JSON-RPC call failed: %s", s);
|
||||
|
||||
free(s);
|
||||
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
// if (hi.reason)
|
||||
// json_object_set_new(val, "reject-reason", json_string(hi.reason));
|
||||
|
||||
databuf_free(&all_data);
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_reset(curl);
|
||||
return val;
|
||||
|
||||
err_out:
|
||||
free(hi.lp_path);
|
||||
free(hi.reason);
|
||||
free(hi.stratum_url);
|
||||
databuf_free(&all_data);
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_reset(curl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
bool rpc_curl_connected(YAAMP_RPC *rpc)
|
||||
{
|
||||
return (curl != NULL);
|
||||
}
|
||||
|
||||
void rpc_curl_close(YAAMP_RPC *rpc)
|
||||
{
|
||||
if(!rpc_curl_connected(rpc)) return;
|
||||
|
||||
//made by rpc_close
|
||||
//pthread_mutex_destroy(&rpc->mutex);
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
curl = NULL;
|
||||
//rpc->sock = 0;
|
||||
}
|
||||
|
||||
bool rpc_curl_connect(YAAMP_RPC *rpc)
|
||||
{
|
||||
rpc_curl_close(rpc);
|
||||
|
||||
//made by rpc_connect
|
||||
//yaamp_create_mutex(&rpc->mutex);
|
||||
|
||||
rpc->id = 0;
|
||||
rpc->bufpos = 0;
|
||||
curl = curl_easy_init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
int rpc_curl_send(YAAMP_RPC *rpc, const char *format, ...)
|
||||
{
|
||||
if(!rpc_curl_connected(rpc)) return -1;
|
||||
|
||||
char buffer[YAAMP_SMALLBUFSIZE] = { 0 };
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vsprintf(buffer, format, args);
|
||||
va_end(args);
|
||||
|
||||
int bytes = strlen(buffer);
|
||||
if(bytes + rpc->bufpos > YAAMP_SMALLBUFSIZE)
|
||||
return -1;
|
||||
|
||||
memcpy(rpc->buffer + rpc->bufpos, buffer, bytes);
|
||||
rpc->bufpos += bytes;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static json_value *rpc_curl_do_call(YAAMP_RPC *rpc, char const *data)
|
||||
{
|
||||
CommonLock(&rpc->mutex);
|
||||
|
||||
char url[1024];
|
||||
int curl_err = 0;
|
||||
sprintf(url, "http%s://%s:%d", rpc->ssl?"s":"", rpc->host, rpc->port);
|
||||
json_value *res = curl_json_rpc(rpc, url, data, &curl_err);
|
||||
|
||||
CommonUnlock(&rpc->mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
json_value *rpc_curl_call(YAAMP_RPC *rpc, char const *method, char const *params)
|
||||
{
|
||||
// debuglog("%s: %s:%d %s\n", __func__, rpc->host, rpc->port, method);
|
||||
|
||||
int s1 = current_timestamp();
|
||||
if (!curl) {
|
||||
rpc_curl_connect(rpc);
|
||||
}
|
||||
|
||||
if(!rpc_curl_connected(rpc)) return NULL;
|
||||
|
||||
int paramlen = params? strlen(params): 0;
|
||||
|
||||
char *message = (char *)malloc(paramlen+1024);
|
||||
if(!message) return NULL;
|
||||
|
||||
if(params)
|
||||
sprintf(message, "{\"method\":\"%s\",\"params\":%s,\"id\":\"%d\"}", method, params, ++rpc->id);
|
||||
else
|
||||
sprintf(message, "{\"method\":\"%s\",\"id\":\"%d\"}", method, ++rpc->id);
|
||||
|
||||
json_value *json = rpc_curl_do_call(rpc, message);
|
||||
|
||||
free(message);
|
||||
if(!json) return NULL;
|
||||
|
||||
int s2 = current_timestamp();
|
||||
if(s2-s1 > 2000)
|
||||
debuglog("delay rpc_call %s:%d %s in %d ms\n", rpc->host, rpc->port, method, s2-s1);
|
||||
|
||||
if(json->type != json_object)
|
||||
{
|
||||
json_value_free(json);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rpc_curl_close(rpc);
|
||||
|
||||
return json;
|
||||
}
|
|
@ -1,10 +1,7 @@
|
|||
|
||||
CC=gcc
|
||||
|
||||
#CFLAGS=-c -g -I /usr/include/mysql
|
||||
#LDFLAGS=-g
|
||||
|
||||
CFLAGS=-c -O3 -I /usr/include/mysql -march=native
|
||||
CFLAGS= -O3 -march=native
|
||||
LDFLAGS=-O2
|
||||
|
||||
SOURCES=sph_jh.c sph_blake.c sph_bmw.c sph_groestl.c sph_skein.c sph_keccak.c sph_luffa.c sph_cubehash.c sph_shavite.c \
|
||||
|
@ -20,10 +17,10 @@ $(OUTPUT): $(OBJECTS)
|
|||
ar rc $@ $(OBJECTS)
|
||||
|
||||
.cpp.o:
|
||||
$(CC) $(CFLAGS) $<
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $<
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
clean:
|
||||
rm *.o
|
||||
|
|
|
@ -63,14 +63,14 @@ json_value *socket_nextjson(YAAMP_SOCKET *s, YAAMP_CLIENT *client)
|
|||
s->buflen += len;
|
||||
s->buffer[s->buflen] = 0;
|
||||
|
||||
// if(client && client->logtraffic)
|
||||
// stratumlog("recv: %s\n", s->buffer);
|
||||
if(client && client->logtraffic)
|
||||
stratumlog("recv: %d\n", s->buflen);
|
||||
|
||||
// pthread_mutex_lock(&s->mutex);
|
||||
}
|
||||
|
||||
char *p = strchr(s->buffer, '}');
|
||||
if(!p)
|
||||
char *b = strchr(s->buffer, '{');
|
||||
if(!b)
|
||||
{
|
||||
if(client)
|
||||
clientlog(client, "bad json");
|
||||
|
@ -79,6 +79,16 @@ json_value *socket_nextjson(YAAMP_SOCKET *s, YAAMP_CLIENT *client)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
char *p = strchr(b, '}');
|
||||
if(!p)
|
||||
{
|
||||
if(client)
|
||||
clientlog(client, "bad json end");
|
||||
|
||||
debuglog("%s\n", b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
char saved = *p;
|
||||
|
@ -87,15 +97,15 @@ json_value *socket_nextjson(YAAMP_SOCKET *s, YAAMP_CLIENT *client)
|
|||
if(client && client->logtraffic)
|
||||
stratumlog("%s, %s, %s, %s, recv: %s\n", client->sock->ip, client->username, client->password, g_current_algo->name, s->buffer);
|
||||
|
||||
int bytes = strlen(s->buffer);
|
||||
int bytes = strlen(b);
|
||||
|
||||
json_value *json = json_parse(s->buffer, bytes);
|
||||
json_value *json = json_parse(b, bytes);
|
||||
if(!json)
|
||||
{
|
||||
if(client)
|
||||
clientlog(client, "bad json parse");
|
||||
|
||||
debuglog("%s\n", s->buffer);
|
||||
debuglog("%s\n", b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,11 +30,9 @@ using namespace std;
|
|||
#include "json.h"
|
||||
#include "util.h"
|
||||
|
||||
#define json_typeof(json) ((json)->type)
|
||||
#define json_is_array(json) (json && json_typeof(json) == json_array)
|
||||
|
||||
#define YAAMP_RESTARTDELAY (24*60*60)
|
||||
#define YAAMP_MAXJOBDELAY (2*60)
|
||||
#define CURL_RPC_TIMEOUT (30)
|
||||
|
||||
#define YAAMP_MS 1000
|
||||
#define YAAMP_SEC 1000000
|
||||
|
|
|
@ -123,7 +123,7 @@ static inline uint16_t le16dec(const void *pp)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static inline uint32_t bswap32(uint32_t x) {
|
||||
__asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x));
|
||||
return x;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue