bool stratum_handle_method_m7(struct stratum_ctx *sctx, const char *s) { json_t *val, *id, *params; json_error_t err; const char *method; bool ret = false; val = JSON_LOADS(s, &err); if (!val) { applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text); goto out; } method = json_string_value(json_object_get(val, "method")); if (!method) goto out; id = json_object_get(val, "id"); params = json_object_get(val, "params"); /* if (!strcasecmp(method, "mining.notify")) { ret = stratum_notify(sctx, params); goto out; } */ if (!strcasecmp(method, "mining.notify")) { // if (opt_algo == ALGO_M7) { ret = stratum_notify_m7(sctx, params); // } else { // ret = stratum_notify(sctx, params); // } goto out; } if (!strcasecmp(method, "mining.set_difficulty")) { ret = stratum_set_difficulty(sctx, params); goto out; } if (!strcasecmp(method, "client.reconnect")) { ret = stratum_reconnect(sctx, params); goto out; } if (!strcasecmp(method, "client.get_version")) { ret = stratum_get_version(sctx, id); goto out; } if (!strcasecmp(method, "client.show_message")) { ret = stratum_show_message(sctx, id, params); goto out; } out: if (val) json_decref(val); return ret; }
bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass) { json_t *val = NULL, *res_val, *err_val; char *s, *sret; json_error_t err; bool ret = false; s = (char*)malloc(80 + strlen(user) + strlen(pass)); sprintf(s, "{\"id\": 2, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}", user, pass); if (!stratum_send_line(sctx, s)) goto out; while (1) { sret = stratum_recv_line(sctx); if (!sret) goto out; if (!stratum_handle_method(sctx, sret)) break; free(sret); } val = JSON_LOADS(sret, &err); free(sret); if (!val) { applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text); goto out; } res_val = json_object_get(val, "result"); err_val = json_object_get(val, "error"); if (!res_val || json_is_false(res_val) || (err_val && !json_is_null(err_val))) { applog(LOG_ERR, "Stratum authentication failed"); goto out; } ret = true; out: free(s); if (val) json_decref(val); return ret; }
static json_t *cjson_decode(void *buf, size_t buflen) { json_t *obj = NULL; json_error_t err; void *obj_unc = NULL; unsigned long dest_len; void *comp_p; uint32_t unc_len; unsigned char zero = 0; if (buflen < 6) return NULL; /* look at first 32 bits of buffer, which contains uncompressed len */ unc_len = le32toh(*((uint32_t *)buf)); if (unc_len > CLI_MAX_MSG) return NULL; /* alloc buffer for uncompressed data */ obj_unc = malloc(unc_len + 1); if (!obj_unc) return NULL; dest_len = unc_len; /* decompress buffer (excluding first 32 bits) */ comp_p = buf + 4; if (uncompress(obj_unc, &dest_len, comp_p, buflen - 4) != Z_OK) goto out; if (dest_len != unc_len) goto out; memcpy(obj_unc + unc_len, &zero, 1); /* null terminate */ /* attempt JSON decode of buffer */ obj = JSON_LOADS(obj_unc, &err); out: free(obj_unc); return obj; }
bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass) { json_t *val = NULL, *res_val, *err_val; char *s, *sret; json_error_t err; bool ret = false; if(jsonrpc_2) { s = (char*)malloc(300 + strlen(user) + strlen(pass)); sprintf(s, "{\"method\": \"login\", \"params\": {\"login\": \"%s\", \"pass\": \"%s\", \"agent\": \"cpuminer-multi/0.1\"}, \"id\": 1}", user, pass); } else { s = (char*)malloc(80 + strlen(user) + strlen(pass)); sprintf(s, "{\"id\": 2, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}", user, pass); } if (!stratum_send_line(sctx, s)) goto out; while (1) { sret = stratum_recv_line(sctx); if (!sret) goto out; if (!stratum_handle_method(sctx, sret)) break; free(sret); } val = JSON_LOADS(sret, &err); free(sret); if (!val) { applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text); goto out; } res_val = json_object_get(val, "result"); err_val = json_object_get(val, "error"); if (!res_val || json_is_false(res_val) || (err_val && !json_is_null(err_val))) { applog(LOG_ERR, "Stratum authentication failed"); goto out; } if(jsonrpc_2) { rpc2_login_decode(val); json_t *job_val = json_object_get(res_val, "job"); pthread_mutex_lock(&sctx->work_lock); if(job_val) rpc2_job_decode(job_val, &sctx->work); pthread_mutex_unlock(&sctx->work_lock); } ret = true; out: free(s); if (val) json_decref(val); return ret; }
bool stratum_subscribe(struct stratum_ctx *sctx) { if(jsonrpc_2) return true; char *s, *sret = NULL; const char *sid, *xnonce1; int xn2_size; json_t *val = NULL, *res_val, *err_val; json_error_t err; bool ret = false, retry = false; start: s = (char*)malloc(128 + (sctx->session_id ? strlen(sctx->session_id) : 0)); if (retry) sprintf(s, "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": []}"); else if (sctx->session_id) sprintf(s, "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": [\"" USER_AGENT "\", \"%s\"]}", sctx->session_id); else sprintf(s, "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": [\"" USER_AGENT "\"]}"); if (!stratum_send_line(sctx, s)) goto out; if (!socket_full(sctx->sock, 30)) { applog(LOG_ERR, "stratum_subscribe timed out"); goto out; } sret = stratum_recv_line(sctx); if (!sret) goto out; val = JSON_LOADS(sret, &err); free(sret); if (!val) { applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text); goto out; } 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))) { if (opt_debug || retry) { free(s); if (err_val) s = json_dumps(err_val, JSON_INDENT(3)); else s = strdup("(unknown reason)"); applog(LOG_ERR, "JSON-RPC call failed: %s", s); } goto out; } sid = get_stratum_session_id(res_val); if (opt_debug && !sid) applog(LOG_DEBUG, "Failed to get Stratum session id"); xnonce1 = json_string_value(json_array_get(res_val, 1)); if (!xnonce1) { applog(LOG_ERR, "Failed to get extranonce1"); goto out; } xn2_size = json_integer_value(json_array_get(res_val, 2)); if (!xn2_size) { applog(LOG_ERR, "Failed to get extranonce2_size"); goto out; } pthread_mutex_lock(&sctx->work_lock); free(sctx->session_id); free(sctx->xnonce1); sctx->session_id = sid ? strdup(sid) : NULL; sctx->xnonce1_size = strlen(xnonce1) / 2; sctx->xnonce1 = (unsigned char*)malloc(sctx->xnonce1_size); hex2bin(sctx->xnonce1, xnonce1, sctx->xnonce1_size); sctx->xnonce2_size = xn2_size; sctx->next_diff = 1.0; pthread_mutex_unlock(&sctx->work_lock); if (opt_debug && sid) applog(LOG_DEBUG, "Stratum session id: %s", sctx->session_id); ret = true; out: free(s); if (val) json_decref(val); if (!ret) { if (sret && !retry) { retry = true; goto start; } } return ret; }
json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass, const char *rpc_req, bool longpoll_scan, bool longpoll, int *curl_err) { json_t *val, *err_val, *res_val; int rc; struct data_buffer all_data = {0}; 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]; long timeout = longpoll ? opt_timeout : 30; struct header_info hi = {0}; bool lp_scanning = longpoll_scan && !have_longpoll; /* 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 (opt_cert) curl_easy_setopt(curl, CURLOPT_CAINFO, opt_cert); curl_easy_setopt(curl, CURLOPT_ENCODING, ""); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); 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 (userpass) { curl_easy_setopt(curl, CURLOPT_USERPWD, userpass); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } #if LIBCURL_VERSION_NUM >= 0x070f06 if (longpoll) curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_keepalive_cb); #endif curl_easy_setopt(curl, CURLOPT_POST, 1); if (opt_protocol) applog(LOG_DEBUG, "JSON protocol request:\n%s\n", 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, "User-Agent: " USER_AGENT); headers = curl_slist_append(headers, "X-Mining-Extensions: midstate"); 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 (!(longpoll && rc == CURLE_OPERATION_TIMEDOUT)) applog(LOG_ERR, "HTTP request failed: %s", curl_err_str); goto err_out; } /* If X-Stratum was found, activate Stratum */ if (want_stratum && hi.stratum_url && !strncasecmp(hi.stratum_url, "stratum+tcp://", 14) && !(opt_proxy && opt_proxy_type == CURLPROXY_HTTP)) { have_stratum = true; tq_push(thr_info[stratum_thr_id].q, hi.stratum_url); hi.stratum_url = NULL; } /* If X-Long-Polling was found, activate long polling */ if (lp_scanning && hi.lp_path && !have_stratum) { have_longpoll = true; tq_push(thr_info[longpoll_thr_id].q, hi.lp_path); hi.lp_path = NULL; } if (!all_data.buf) { applog(LOG_ERR, "Empty data received in json_rpc_call."); goto err_out; } val = JSON_LOADS((const char*)all_data.buf, &err); if (!val) { applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text); goto err_out; } if (opt_protocol) { char *s = json_dumps(val, JSON_INDENT(3)); applog(LOG_DEBUG, "JSON protocol response:\n%s", 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)"); applog(LOG_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; }
json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass, const char *rpc_req, bool probe, bool longpoll, int *rolltime, struct pool *pool, bool share) { long timeout = longpoll ? (60 * 60) : 60; struct data_buffer all_data = {NULL, 0}; struct header_info hi = {NULL, 0, NULL, NULL, false, false, false}; char len_hdr[64], user_agent_hdr[128]; char curl_err_str[CURL_ERROR_SIZE]; struct curl_slist *headers = NULL; struct upload_buffer upload_data; json_t *val, *err_val, *res_val; bool probing = false; double byte_count; json_error_t err; int rc; memset(&err, 0, sizeof(err)); /* it is assumed that 'curl' is freshly [re]initialized at this pt */ if (probe) probing = !pool->probed; curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); // CURLOPT_VERBOSE won't write to stderr if we use CURLOPT_DEBUGFUNCTION curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_debug_cb); curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)pool); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_ENCODING, ""); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); /* Shares are staggered already and delays in submission can be costly * so do not delay them */ if (!opt_delaynet || share) 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); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, resp_hdr_cb); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &hi); curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); 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); } if (userpass) { curl_easy_setopt(curl, CURLOPT_USERPWD, userpass); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } if (longpoll) keep_curlalive(curl); curl_easy_setopt(curl, CURLOPT_POST, 1); if (opt_protocol) applog(LOG_DEBUG, "JSON protocol request:\n%s", rpc_req); upload_data.buf = rpc_req; upload_data.len = strlen(rpc_req); sprintf(len_hdr, "Content-Length: %lu", (unsigned long) upload_data.len); sprintf(user_agent_hdr, "User-Agent: %s", PACKAGE_STRING); headers = curl_slist_append(headers, "Content-type: application/json"); headers = curl_slist_append(headers, "X-Mining-Extensions: longpoll midstate rollntime submitold"); if (likely(global_hashrate)) { char ghashrate[255]; sprintf(ghashrate, "X-Mining-Hashrate: %llu", global_hashrate); headers = curl_slist_append(headers, ghashrate); } headers = curl_slist_append(headers, len_hdr); headers = curl_slist_append(headers, user_agent_hdr); headers = curl_slist_append(headers, "Expect:"); /* disable Expect hdr*/ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); if (opt_delaynet) { /* Don't delay share submission, but still track the nettime */ if (!share) { long long now_msecs, last_msecs; struct timeval2 now, last; gettimeofday(&now, NULL); last_nettime(&last); now_msecs = (long long)now.tv_sec * 1000; now_msecs += now.tv_usec / 1000; last_msecs = (long long)last.tv_sec * 1000; last_msecs += last.tv_usec / 1000; if (now_msecs > last_msecs && now_msecs - last_msecs < 250) { struct timespec rgtp; rgtp.tv_sec = 0; rgtp.tv_nsec = (250 - (now_msecs - last_msecs)) * 1000000; nanosleep(&rgtp, NULL); } } set_nettime(); } rc = curl_easy_perform(curl); if (rc) { applog(LOG_INFO, "HTTP request failed: %s", curl_err_str); goto err_out; } if (!all_data.buf) { applog(LOG_DEBUG, "Empty data received in json_rpc_call."); goto err_out; } pool->cgminer_pool_stats.times_sent++; if (curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &byte_count) == CURLE_OK) pool->cgminer_pool_stats.bytes_sent += byte_count; pool->cgminer_pool_stats.times_received++; if (curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &byte_count) == CURLE_OK) pool->cgminer_pool_stats.bytes_received += byte_count; if (probing) { pool->probed = true; /* If X-Long-Polling was found, activate long polling */ if (hi.lp_path) { if (pool->hdr_path != NULL) free(pool->hdr_path); pool->hdr_path = hi.lp_path; } else pool->hdr_path = NULL; if (hi.stratum_url) { pool->stratum_url = hi.stratum_url; hi.stratum_url = NULL; } } else { if (hi.lp_path) { free(hi.lp_path); hi.lp_path = NULL; } if (hi.stratum_url) { free(hi.stratum_url); hi.stratum_url = NULL; } } *rolltime = hi.rolltime; pool->cgminer_pool_stats.rolltime = hi.rolltime; pool->cgminer_pool_stats.hadrolltime = hi.hadrolltime; pool->cgminer_pool_stats.canroll = hi.canroll; pool->cgminer_pool_stats.hadexpire = hi.hadexpire; val = JSON_LOADS(all_data.buf, &err); if (!val) { applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text); if (opt_protocol) applog(LOG_DEBUG, "JSON protocol response:\n%s", all_data.buf); goto err_out; } if (opt_protocol) { char *s = json_dumps(val, JSON_INDENT(3)); applog(LOG_DEBUG, "JSON protocol response:\n%s", 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 ||(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)"); applog(LOG_INFO, "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)); free(hi.reason); hi.reason = NULL; } successful_connect = true; databuf_free(&all_data); curl_slist_free_all(headers); curl_easy_reset(curl); return val; err_out: databuf_free(&all_data); curl_slist_free_all(headers); curl_easy_reset(curl); if (!successful_connect) applog(LOG_DEBUG, "Failed to connect in json_rpc_call"); curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); return NULL; }
static void http_handle_req(struct evhttp_request *req, lp_type longpoll, bool *req_valid) { const char *clen_str; char *body_str; char username[65] = ""; void *body, *reply = NULL; int clen = 0; unsigned int reply_len = 0; json_t *jreq; json_error_t jerr; bool rc; struct evbuffer *evbuf; if (!http_get_username(req, username, req->chunked)) return; if (longpoll == LP_NONE) { clen_str = evhttp_find_header(req->input_headers, "Content-Length"); if (clen_str) clen = atoi(clen_str); if (clen < 1 || clen > 999999) { reqlog(req->remote_host, username, req->uri); goto err_out_bad_req; } if (EVBUFFER_LENGTH(req->input_buffer) != clen) goto err_out_bad_req; body = EVBUFFER_DATA(req->input_buffer); body_str = strndup(body, clen); if (!body_str) goto err_out_bad_req; } else if (longpoll == LP_REPLY) { body_str = strdup("{\"method\":\"getwork\",\"params\":[],\"id\":1}"); } else if (longpoll == LP_KEEPALIVE || longpoll == LP_CLOSE) { reply = malloc(sizeof(char) * 2); if (!reply) goto err_out_bad_req; reply_len = snprintf(reply, 2, " "); } if (!reply) { jreq = JSON_LOADS(body_str, &jerr); free(body_str); if (!jreq) goto err_out_bad_req; rc = msg_json_rpc(req, jreq, username, &reply, &reply_len); json_decref(jreq); if (!rc) goto err_out_bad_req; } evbuf = evbuffer_new(); if (!evbuf) { free(reply); goto err_out_bad_req; } if (evbuffer_add(evbuf, reply, reply_len)) { evbuffer_free(evbuf); free(reply); goto err_out_bad_req; } free(reply); /* req_valid is a pointer to the valid member of the list struct * containing the LP request. When the connection drops and * http_lp_close_cb is called, this bool is set to false. Because we * have the reference, we can check before each send command if the * close callback has been called or if the request is still OK. * * We only have to check this when sending chunked, because if we send * in one go, there is nothing that could have closed the request, as * we're single threaded. For now. */ if (longpoll == LP_NONE) { /* Send normal requests not chunked */ evhttp_send_reply(req, HTTP_OK, "ok", evbuf); } else { if (!req->chunked && is_valid(req_valid)) evhttp_send_reply_start(req, HTTP_OK, "ok"); if (is_valid(req_valid)) evhttp_send_reply_chunk(req, evbuf); if (longpoll != LP_KEEPALIVE && is_valid(req_valid)) evhttp_send_reply_end(req); } evbuffer_free(evbuf); return; err_out_bad_req: /* When we've already sent headers, we can't really give an error so * we just send an empty reply... */ if (req->chunked) { if (is_valid(req_valid)) evhttp_send_reply_end(req); } else { evhttp_send_reply(req, HTTP_BADREQUEST, "invalid args", NULL); } }
json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass, const char *rpc_req) { 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]; /* it is assumed that 'curl' is freshly [re]initialized at this pt */ if (debugging > 1) 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 (debugging > 1) 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) { applog(LOG_ERR, "HTTP request failed: %s", curl_err_str); goto err_out; } val = JSON_LOADS(all_data.buf, &err); if (!val) { applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text); goto err_out; } if (debugging > 1) { 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)"); applog(LOG_ERR, "JSON-RPC call failed: %s", s); free(s); goto err_out; } databuf_free(&all_data); curl_slist_free_all(headers); curl_easy_reset(curl); return val; err_out: databuf_free(&all_data); curl_slist_free_all(headers); curl_easy_reset(curl); return NULL; }
void read_config(void) { json_t *jcfg, *cred_expire; json_error_t err; const char *tmp_str, *rpcuser, *rpcpass; char *file_data; file_data = read_commented_file(srv.config); if (!file_data) exit(1); jcfg = JSON_LOADS(file_data, &err); free(file_data); if (!jcfg) { applog(LOG_ERR, "%s: JSON parse failed", srv.config); exit(1); } if (!json_is_object(jcfg)) { applog(LOG_ERR, "top-level JSON value not an object"); exit(1); } parse_listen(json_object_get(jcfg, "listen")); parse_database(json_object_get(jcfg, "database")); parse_memcached(json_object_get(jcfg, "memcached")); if (elist_empty(&srv.listeners)) { applog(LOG_ERR, "error: no listen addresses specified"); exit(1); } tmp_str = json_string_value(json_object_get(jcfg, "pid")); if (tmp_str) srv.pid_file = strdup(tmp_str); tmp_str = json_string_value(json_object_get(jcfg, "forcehost")); if (tmp_str) srv.ourhost = strdup(tmp_str); srv.any_password = (json_is_true(json_object_get(jcfg, "any_password"))) ? true : false; srv.bother_upstream = (json_is_true(json_object_get(jcfg, "bother_upstream"))) ? true : false; tmp_str = json_string_value(json_object_get(jcfg, "log.requests")); if (tmp_str) { srv.req_log = strdup(tmp_str); srv.req_fd = open(srv.req_log, O_WRONLY | O_CREAT | O_APPEND, 0666); if (srv.req_fd < 0) { syslogerr(srv.req_log); exit(1); } } tmp_str = json_string_value(json_object_get(jcfg, "log.shares")); if (tmp_str) { srv.share_log = strdup(tmp_str); srv.share_fd = open(srv.share_log, O_WRONLY | O_CREAT | O_APPEND, 0666); if (srv.share_fd < 0) { syslogerr(srv.share_log); exit(1); } } if (json_is_true(json_object_get(jcfg, "longpoll.disable"))) srv.disable_lp = true; cred_expire = json_object_get(jcfg, "auth.cred_cache.expire"); if (json_is_integer(cred_expire)) srv.cred_expire = json_integer_value(cred_expire); tmp_str = json_string_value(json_object_get(jcfg, "rpc.url")); if (!tmp_str) { applog(LOG_ERR, "error: no RPC URL specified"); exit(1); } srv.rpc_url = strdup(tmp_str); rpcuser = json_string_value(json_object_get(jcfg, "rpc.user")); rpcpass = json_string_value(json_object_get(jcfg, "rpc.pass")); if (!rpcuser || !rpcpass) { applog(LOG_ERR, "error: no RPC user and/or password specified"); exit(1); } if (asprintf(&srv.rpc_userpass, "%s:%s", rpcuser, rpcpass) < 0) { applog(LOG_ERR, "OOM"); exit(1); } if (json_is_true(json_object_get(jcfg, "rpc.target.rewrite"))) srv.easy_target = json_string(EASY_TARGET); if (!srv.pid_file) { if (!(srv.pid_file = strdup("/var/run/pushpoold.pid"))) { applog(LOG_ERR, "no core"); exit(1); } } if (json_is_true(json_object_get(jcfg, "roll.ntime.disable"))) srv.disable_roll_ntime = true; json_decref(jcfg); }