/****************************************************************************** * Copyright © 2014-2017 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ #include "OS_portable.h" #define LIQUIDITY_PROVIDER 1 #if LIQUIDITY_PROVIDER #include #include // return data from the server #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) #define CURL_GLOBAL_SSL (1<<0) #define CURL_GLOBAL_WIN32 (1<<1) struct return_string { char *ptr; size_t len; }; size_t accumulate(void *ptr, size_t size, size_t nmemb, struct return_string *s); void init_string(struct return_string *s); /************************************************************************ * * return the current system time in milliseconds * ************************************************************************/ #define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field #ifdef EXTRACT_BITCOIND_RESULT /************************************************************************ * * perform post processing of the results * ************************************************************************/ char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params) { long i,j,len; char *retstr = 0; cJSON *json,*result,*error; //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 ) { if ( strcmp(command,"signrawtransaction") != 0 && strcmp(command,"getrawtransaction") != 0 ) printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); return(rpcstr); } json = cJSON_Parse(rpcstr); if ( json == 0 ) { printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params); free(rpcstr); return(0); } result = cJSON_GetObjectItem(json,"result"); error = cJSON_GetObjectItem(json,"error"); if ( error != 0 && result != 0 ) { if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL ) { retstr = cJSON_Print(result); len = strlen(retstr); if ( retstr[0] == '"' && retstr[len-1] == '"' ) { for (i=1,j=0; itype&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL ) { if ( strcmp(command,"getrawtransaction") != 0 && strcmp(command,"signrawtransaction") != 0 && strcmp(command,"sendrawtransaction") != 0 ) printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr); retstr = rpcstr; rpcstr = 0; } if ( rpcstr != 0 ) free(rpcstr); } else retstr = rpcstr; free_json(json); //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr); return(retstr); } #endif /************************************************************************ * * perform the query * ************************************************************************/ static int32_t USE_JAY; char *Jay_NXTrequest(char *command,char *params) { char *retstr = 0; // issue JS Jay request // wait till it is done return(retstr); } char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params,int32_t timeout) { static int didinit,count,count2; static double elapsedsum,elapsedsum2; extern int32_t USE_JAY; struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle; char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime; if ( didinit == 0 ) { didinit = 1; curl_global_init(CURL_GLOBAL_ALL); //init the curl session } if ( (0) && (USE_JAY != 0 && (strncmp(url,"http://127.0.0.1:7876/nxt",strlen("http://127.0.0.1:7876/nxt")) == 0 || strncmp(url,"https://127.0.0.1:7876/nxt",strlen("https://127.0.0.1:7876/nxt")) == 0)) ) { if ( (databuf= Jay_NXTrequest(command,params)) != 0 ) return(databuf); } numretries = 0; if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 ) specialcase = 1; else specialcase = 0; if ( url[0] == 0 ) strcpy(url,"http://127.0.0.1:7776"); if ( specialcase != 0 && (0) ) printf("<<<<<<<<<<< bitcoind_RPC: userpass.(%s) url.(%s) command.(%s) params.(%s)\n",userpass,url,command,params); try_again: if ( retstrp != 0 ) *retstrp = 0; starttime = OS_milliseconds(); curl_handle = curl_easy_init(); init_string(&s); headers = curl_slist_append(0,"Expect:"); curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl_handle,CURLOPT_URL, url); curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulate); // send all data to this function curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback if ( timeout > 0 ) curl_easy_setopt(curl_handle,CURLOPT_TIMEOUT, timeout); // causes problems with iguana timeouts if ( strncmp(url,"https",5) == 0 ) { curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0); } if ( userpass != 0 ) curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass); databuf = 0; if ( params != 0 ) { if ( command != 0 && specialcase == 0 ) { len = strlen(params); if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) { bracket0 = bracket1 = (char *)""; } else { bracket0 = (char *)"["; bracket1 = (char *)"]"; } char agentstr[64]; databuf = (char *)malloc(256 + strlen(command) + strlen(params)); if ( debugstr[0] != 0 ) sprintf(agentstr,"\"agent\":\"%s\",",debugstr); else agentstr[0] = 0; sprintf(databuf,"{\"id\":\"jl777\",%s\"method\":\"%s\",\"params\":%s%s%s}",agentstr,command,bracket0,params,bracket1); //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); // } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params); curl_easy_setopt(curl_handle,CURLOPT_POST,1L); if ( databuf != 0 ) curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf); else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params); } //laststart = milliseconds(); res = curl_easy_perform(curl_handle); curl_slist_free_all(headers); curl_easy_cleanup(curl_handle); if ( databuf != 0 ) // clean up temporary buffer { free(databuf); databuf = 0; } if ( res != CURLE_OK ) { numretries++; if ( specialcase != 0 ) { printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); free(s.ptr); return(0); } else if ( numretries >= 4 ) { printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries); //printf("Maximum number of retries exceeded!\n"); free(s.ptr); return(0); } free(s.ptr); sleep((1< (%s)\n",params,s.ptr); count2++; elapsedsum2 += (OS_milliseconds() - starttime); if ( (count2 % 10000) == 0) printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command); return(s.ptr); } } //printf("bitcoind_RPC: impossible case\n"); //free(s.ptr); //return(0); } /************************************************************************ * * Initialize the string handler so that it is thread safe * ************************************************************************/ void init_string(struct return_string *s) { s->len = 0; s->ptr = (char *)calloc(1,s->len+1); if ( s->ptr == NULL ) { fprintf(stderr,"init_string malloc() failed\n"); exit(-1); } s->ptr[0] = '\0'; } /************************************************************************ * * Use the "writer" to accumulate text until done * ************************************************************************/ size_t accumulate(void *ptr,size_t size,size_t nmemb,struct return_string *s) { size_t new_len = s->len + size*nmemb; s->ptr = (char *)realloc(s->ptr,new_len+1); if ( s->ptr == NULL ) { fprintf(stderr, "accumulate realloc() failed\n"); exit(-1); } memcpy(s->ptr+s->len,ptr,size*nmemb); s->ptr[new_len] = '\0'; s->len = new_len; return(size * nmemb); } struct MemoryStruct { char *memory; size_t size; }; static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data) { size_t realsize = (size * nmemb); struct MemoryStruct *mem = (struct MemoryStruct *)data; mem->memory = (ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1); if ( mem->memory != 0 ) { if ( ptr != 0 ) memcpy(&(mem->memory[mem->size]),ptr,realsize); mem->size += realsize; mem->memory[mem->size] = 0; } //printf("got %d bytes\n",(int32_t)(size*nmemb)); return(realsize); } void *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3) { struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0; if ( (cHandle= *cHandlep) == NULL ) *cHandlep = cHandle = curl_easy_init(); else curl_easy_reset(cHandle); //#ifdef DEBUG //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1); //#endif curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0); //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1); curl_easy_setopt(cHandle,CURLOPT_URL,url); curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10); if ( userpass != 0 && userpass[0] != 0 ) curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass); if ( postfields != 0 && postfields[0] != 0 ) { curl_easy_setopt(cHandle,CURLOPT_POST,1); curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields); } if ( hdr0 != NULL && hdr0[0] != 0 ) { //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:""); headers = curl_slist_append(headers,hdr0); if ( hdr1 != 0 && hdr1[0] != 0 ) headers = curl_slist_append(headers,hdr1); if ( hdr2 != 0 && hdr2[0] != 0 ) headers = curl_slist_append(headers,hdr2); if ( hdr3 != 0 && hdr3[0] != 0 ) headers = curl_slist_append(headers,hdr3); } //headers = curl_slist_append(0,"Expect:"); if ( headers != 0 ) curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers); //res = curl_easy_perform(cHandle); memset(&chunk,0,sizeof(chunk)); curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback); curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk); curl_easy_perform(cHandle); curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code); if ( headers != 0 ) curl_slist_free_all(headers); if ( code != 200 ) printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory); return(chunk.memory); } void curlhandle_free(void *curlhandle) { curl_easy_cleanup(curlhandle); } #else char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params) { return(clonestr("{\"error\":\"curl is disabled\"}")); } void *curl_post(void **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3) { return(clonestr("{\"error\":\"curl is disabled\"}")); } #endif