int main(int argc, char **argv) { size_t size = 0; DataBuf buf; char *data; assert(databuf_init(&buf, size, DATABUF_FLAG_STRING)); databuf_print(&buf, 1, "after init size=%d", size); #if 1 data = "a"; assert(databuf_strcat(&buf, data)); databuf_print(&buf, 1, "after strcat(%s)", data); data = "bb"; assert(databuf_strcat(&buf, data)); databuf_print(&buf, 1, "after strcat(%s)", data); data = "ccc"; assert(databuf_strcat(&buf, data)); databuf_print(&buf, 1, "after strcat(%s)", data); #endif databuf_free(&buf); #if 0 assert(databuf_init(&buf, size, 0)); databuf_print(&buf, 1, "after init size=%d", size); size = 8; data = make_data(size, "a"); assert(databuf_append(&buf, data, size)); databuf_print(&buf, 1, "after append size=%d", size); assert(databuf_append(&buf, data, size)); free(data); databuf_print(&buf, 1, "after append size=%d", size); assert(databuf_advance(&buf, 4)); databuf_print(&buf, 1, "after databuf_advance(%d", 4); size = 5; data = make_data(size, "b"); assert(databuf_append(&buf, data, size)); free(data); databuf_print(&buf, 1, "after append size=%d", size); size = 7; data = make_data(size, "c"); assert(databuf_append(&buf, data, size)); free(data); databuf_print(&buf, 1, "after append size=%d", size); databuf_free(&buf); #endif exit(0); }
static void auparse_destroy_common(auparse_state_t *au) { if (au == NULL) return; if (au->source_list) { int n = 0; while (au->source_list[n]) free(au->source_list[n++]); free(au->source_list); au->source_list = NULL; } au->next_buf = NULL; free(au->cur_buf); au->cur_buf = NULL; au->le = NULL; au->parse_state = EVENT_EMPTY; free(au->find_field); au->find_field = NULL; ausearch_clear(au); databuf_free(&au->databuf); if (au->callback_user_data_destroy) { (*au->callback_user_data_destroy)(au->callback_user_data); au->callback_user_data = NULL; } if (au->in) { fclose(au->in); au->in = NULL; } free_interpretation_list(); clear_normalizer(&au->norm_data); au_lol_clear(au->au_lo, 0); free((void *)au->tmp_translation); free(au->au_lo); free(au); }
/* General functions that affect operation of the library */ auparse_state_t *auparse_init(ausource_t source, const void *b) { char **tmp, **bb = (char **)b, *buf = (char *)b; int n, i; size_t size, len; auparse_state_t *au = malloc(sizeof(auparse_state_t)); if (au == NULL) { errno = ENOMEM; return NULL; } au->le = NULL; /* * Set up the List of List events base structure */ au->au_lo = calloc(sizeof(au_lol), 1); if (au->au_lo == NULL) { free(au); errno = ENOMEM; return NULL; } au_lol_clear(au->au_lo, 0); // python doesn't call auparse_destroy if (au_lol_create(au->au_lo) == NULL) { free(au->au_lo); free(au); errno = ENOMEM; return NULL; } au->au_ready = 0; au->in = NULL; au->source_list = NULL; databuf_init(&au->databuf, 0, 0); au->callback = NULL; au->callback_user_data = NULL; au->callback_user_data_destroy = NULL; switch (source) { case AUSOURCE_LOGS: if (setup_log_file_array(au)) goto bad_exit; break; case AUSOURCE_FILE: if (b == NULL) goto bad_exit; if (access(b, R_OK)) goto bad_exit; tmp = malloc(2*sizeof(char *)); tmp[0] = strdup(b); tmp[1] = NULL; au->source_list = tmp; break; case AUSOURCE_FILE_ARRAY: if (bb == NULL) goto bad_exit; n = 0; while (bb[n]) { if (access(bb[n], R_OK)) goto bad_exit; n++; } tmp = malloc((n+1)*sizeof(char *)); for (i=0; i<n; i++) tmp[i] = strdup(bb[i]); tmp[n] = NULL; au->source_list = tmp; break; case AUSOURCE_BUFFER: if (buf == NULL) goto bad_exit; len = strlen(buf); if (databuf_init(&au->databuf, len, DATABUF_FLAG_PRESERVE_HEAD) < 0) goto bad_exit; if (databuf_append(&au->databuf, buf, len) < 0) goto bad_exit; break; case AUSOURCE_BUFFER_ARRAY: if (bb == NULL) goto bad_exit; size = 0; for (n = 0; (buf = bb[n]); n++) { len = strlen(bb[n]); if (bb[n][len-1] != '\n') { size += len + 1; } else { size += len; } } if (databuf_init(&au->databuf, size, DATABUF_FLAG_PRESERVE_HEAD) < 0) goto bad_exit; for (n = 0; (buf = bb[n]); n++) { len = strlen(buf); if (databuf_append(&au->databuf, buf, len) < 0) goto bad_exit; } break; case AUSOURCE_DESCRIPTOR: n = (long)b; au->in = fdopen(n, "rm"); break; case AUSOURCE_FILE_POINTER: au->in = (FILE *)b; break; case AUSOURCE_FEED: if (databuf_init(&au->databuf, 0, 0) < 0) goto bad_exit; break; default: errno = EINVAL; goto bad_exit; break; } au->source = source; au->list_idx = 0; au->line_number = 0; au->next_buf = NULL; au->off = 0; au->cur_buf = NULL; au->line_pushed = 0; au->parse_state = EVENT_EMPTY; au->expr = NULL; au->find_field = NULL; au->search_where = AUSEARCH_STOP_EVENT; au->escape_mode = AUPARSE_ESC_TTY; au->message_mode = MSG_QUIET; au->debug_message = DBG_NO; au->tmp_translation = NULL; init_normalizer(&au->norm_data); return au; bad_exit: databuf_free(&au->databuf); /* Free list of events list (au_lo) structure */ au_lol_clear(au->au_lo, 0); free(au->au_lo); free(au); return NULL; }
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; }
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; }
json_t *json_rpc_call(const char *url, const char *userpass, const char *rpc_req) { CURL *curl; json_t *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]; curl = curl_easy_init(); if (!curl) 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); 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) goto err_out; val = json_loads(all_data.buf, &err); if (!val) { fprintf(stderr, "JSON 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); } 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; }