commits
tags
#include "rpc.h"
#include "http.h"
#include <stdio.h>
#include <string.h>
void rpc_init(RpcClient *c, const char *host, int port, const char *user, const char *pass)
{
memset(c, 0, sizeof(*c));
snprintf(c->host, sizeof(c->host), "%s", host);
c->port = port;
if (user)
snprintf(c->user, sizeof(c->user), "%s", user);
if (pass)
snprintf(c->pass, sizeof(c->pass), "%s", pass);
}
int rpc_call(RpcClient *c, const char *method, cJSON *arguments,
cJSON **out_args, char *err, size_t errlen)
{
if (out_args)
*out_args = NULL;
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "method", method);
if (arguments)
cJSON_AddItemToObject(root, "arguments", arguments);
char *body = cJSON_PrintUnformatted(root);
size_t body_len = strlen(body);
c->last_http_status = 0;
int rc = -1;
for (int attempt = 0; attempt < 2; attempt++) {
HttpResponse resp;
int hrc = http_post_json(c->host, c->port, "/transmission/rpc",
c->user[0] ? c->user : NULL, c->pass,
c->session_id[0] ? c->session_id : NULL,
body, body_len, &resp, err, errlen);
if (hrc != 0) {
rc = -1;
break;
}
c->last_http_status = resp.status;
if (resp.session_id[0])
snprintf(c->session_id, sizeof(c->session_id), "%s", resp.session_id);
if (resp.status == 409 && attempt == 0) {
/* CSRF handshake: retry once now that we have a session id. */
http_response_free(&resp);
continue;
}
if (resp.status != 200) {
snprintf(err, errlen, "HTTP error %d from server", resp.status);
http_response_free(&resp);
rc = -1;
break;
}
cJSON *respjson = cJSON_ParseWithLength(resp.body, resp.body_len);
http_response_free(&resp);
if (!respjson) {
snprintf(err, errlen, "could not parse JSON response");
rc = -1;
break;
}
cJSON *result = cJSON_GetObjectItemCaseSensitive(respjson, "result");
if (!cJSON_IsString(result) || strcmp(result->valuestring, "success") != 0) {
snprintf(err, errlen, "RPC error: %s",
cJSON_IsString(result) ? result->valuestring : "unknown error");
cJSON_Delete(respjson);
rc = -1;
break;
}
if (out_args) {
cJSON *args = cJSON_DetachItemFromObjectCaseSensitive(respjson, "arguments");
*out_args = args;
}
cJSON_Delete(respjson);
rc = 0;
break;
}
cJSON_free(body);
cJSON_Delete(root);
return rc;
}