1

If I want to call the Wallet RPC functions from C++ is there an example of how I can do this. I have something using libcurl but I am unsure if I am doing it correctly.

static size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp) {
  ((std::string *) userp)->append((char *) contents, size * nmemb);
  return size * nmemb;
}


int main() {

  std::string method = "get_balance";
  std::string params = "{"account_index":0,"address_indicies":[0,1]}";

  CURL *curl;
  CURLcode res;
  std::string readBuffer;

  curl = curl_easy_init();
  if (curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:8080/json_rpc");
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
    const std::string &postField = R"({"jsonrpc":"2.0","id":"0","method":")" + method +
                                   R"(","params":)" + params + "}";

    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postField.c_str());

    auto userPassword =  "test:test";


    // Set the authorization to use the username and password.
    curl_easy_setopt(curl, CURLOPT_USERPWD, userPassword.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);


    // Give a call back function and a string to write the callback data into.
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);

    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);

    // Set the content type to be application json.
    struct curl_slist *hs=NULL;
    hs = curl_slist_append(hs, "Accept: application/json");
    hs = curl_slist_append(hs, "Content-Type: application/json");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);

    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}

Right now, this just repeatedly retries and the verbose looks like the following.

*   Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 () port 8080 (#0)
* Server auth using Digest with user 'test'
> POST /json_rpc HTTP/1.1
Host: 127.0.0.1:8080
Accept: */*
Content-Length: 0
Content-Type: application/x-www-form-urlencoded

* Mark bundle as not supporting multiuse
< HTTP/1.1 401 Unauthorized
< Server: Epee-based
< Content-Length: 98
< Content-Type: text/html
< Last-Modified: Sat, 14 Nov 2020 19:22:09 GMT
< Accept-Ranges: bytes
< WWW-authenticate: Digest qop="auth",algorithm=MD5,realm="monero-rpc",nonce="FRml5Rcf3sdumCrp0VyFzg==",stale=false
* Ignoring duplicate digest auth header.
< WWW-authenticate: Digest qop="auth",algorithm=MD5-sess,realm="monero-rpc",nonce="FRml5Rcf3sdumCrp0VyFzg==",stale=false
< 
* Ignoring the response-body
* Connection #0 to host 127.0.0.1 left intact
* Issue another request to this URL: 'http://127.0.0.1:8080/json_rpc'
* Found bundle for host 127.0.0.1: 0x562551d5ca00 [serially]
* Connection #0 is still name resolving, can't reuse
* Hostname 127.0.0.1 was found in DNS cache
  • I suspect part of your problem is the fact you use CURLOPT_CUSTOMREQUEST rather than CURLOPT_POST. From the curl docs: "Many people have wrongly used this option to replace the entire request with their own, including multiple headers and POST contents. While that might work in many cases, it will cause libcurl to send invalid requests and it could possibly confuse the remote server badly.". – jtgrassie Nov 14 at 19:55
  • Okay I have fixed that bit. I am still getting the 401 unauthorized. I checked and my code works if I do --disable-rpc-login but I assume that is fairly unsafe. – Keiros Nov 14 at 20:13
  • You also don't have any redirect/location handling in your code. When auth is used, you will get a redirection for authentication. – jtgrassie Nov 14 at 20:21
  • You mean a READDATA? – Keiros Nov 14 at 20:24
  • No. That is a read data option that has nothing to do with redirection. See options like CURLOPT_POSTREDIR / CURLOPT_FOLLOWLOCATION. – jtgrassie Nov 14 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.