/* * Copyright 2010 Jeff Garzik * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. See COPYING for more details. */ #define _GNU_SOURCE #include "cpuminer-config.h" #include #include #include #include #include #include "miner.h" struct data_buffer { void *buf; size_t len; }; struct upload_buffer { const void *buf; size_t len; }; 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 = user_data; size_t len = size * nmemb; size_t oldlen, newlen; void *newmem; static const unsigned char zero; oldlen = db->len; newlen = oldlen + len; newmem = realloc(db->buf, newlen + 1); if (!newmem) return 0; db->buf = newmem; db->len = newlen; memcpy(db->buf + oldlen, ptr, len); memcpy(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 = user_data; int len = size * nmemb; if (len > ub->len) len = ub->len; if (len) { memcpy(ptr, ub->buf, len); ub->buf += len; ub->len -= len; } return len; } json_t *json_rpc_call(const char *url, const char *userpass, const char *rpc_req) { CURL *curl; json_t *val, *err_val, *res_val; int rc; struct data_buffer all_data = { }; struct upload_buffer upload_data; json_error_t err = { }; struct curl_slist *headers = NULL; char len_hdr[64]; char curl_err_str[CURL_ERROR_SIZE]; curl = curl_easy_init(); if (!curl) { fprintf(stderr, "CURL initialization failed, aborting JSON-RPC call\n"); return NULL; } if (opt_protocol) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_ENCODING, ""); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 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); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_str); if (userpass) { curl_easy_setopt(curl, CURLOPT_USERPWD, userpass); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } curl_easy_setopt(curl, CURLOPT_POST, 1); if (opt_protocol) printf("JSON protocol request:\n%s\n", rpc_req); upload_data.buf = rpc_req; upload_data.len = strlen(rpc_req); 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, "Expect:"); /* disable Expect hdr*/ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); rc = curl_easy_perform(curl); if (rc) { fprintf(stderr, "HTTP request failed: %s\n", curl_err_str); goto err_out; } val = json_loads(all_data.buf, &err); if (!val) { fprintf(stderr, "JSON decode failed(%d): %s\n", err.line, err.text); goto err_out; } if (opt_protocol) { char *s = json_dumps(val, JSON_INDENT(3)); printf("JSON protocol response:\n%s\n", s); 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; if (err_val) s = json_dumps(err_val, JSON_INDENT(3)); else s = strdup("(unknown reason)"); fprintf(stderr, "JSON-RPC call failed: %s\n", s); free(s); goto err_out; } databuf_free(&all_data); curl_slist_free_all(headers); curl_easy_cleanup(curl); return val; err_out: databuf_free(&all_data); curl_slist_free_all(headers); curl_easy_cleanup(curl); return NULL; } char *bin2hex(unsigned char *p, size_t len) { int i; char *s = malloc((len * 2) + 1); if (!s) return NULL; for (i = 0; i < len; i++) sprintf(s + (i * 2), "%02x", (unsigned int) p[i]); return s; } bool hex2bin(unsigned char *p, const char *hexstr, size_t len) { while (*hexstr && len) { char hex_byte[3]; unsigned int v; if (!hexstr[1]) { fprintf(stderr, "hex2bin str truncated\n"); return false; } hex_byte[0] = hexstr[0]; hex_byte[1] = hexstr[1]; hex_byte[2] = 0; if (sscanf(hex_byte, "%x", &v) != 1) { fprintf(stderr, "hex2bin sscanf '%s' failed\n", hex_byte); return false; } *p = (unsigned char) v; p++; hexstr += 2; len--; } return (len == 0 && *hexstr == 0) ? true : false; } /* Subtract the `struct timeval' values X and Y, storing the result in RESULT. Return 1 if the difference is negative, otherwise 0. */ int timeval_subtract ( struct timeval *result, struct timeval *x, struct timeval *y) { /* Perform the carry for the later subtraction by updating Y. */ if (x->tv_usec < y->tv_usec) { int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; y->tv_usec -= 1000000 * nsec; y->tv_sec += nsec; } if (x->tv_usec - y->tv_usec > 1000000) { int nsec = (x->tv_usec - y->tv_usec) / 1000000; y->tv_usec += 1000000 * nsec; y->tv_sec -= nsec; } /* Compute the time remaining to wait. `tv_usec' is certainly positive. */ result->tv_sec = x->tv_sec - y->tv_sec; result->tv_usec = x->tv_usec - y->tv_usec; /* Return 1 if result is negative. */ return x->tv_sec < y->tv_sec; }