xref: /spdk/lib/jsonrpc/jsonrpc_client.c (revision a6dbe3721eb3b5990707fc3e378c95e505dd8ab5)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse  *   Copyright (C) 2018 Intel Corporation.
3c10f8e16SLiu Xiaodong  *   All rights reserved.
4c10f8e16SLiu Xiaodong  */
5c10f8e16SLiu Xiaodong 
6c10f8e16SLiu Xiaodong #include "spdk/util.h"
7c10f8e16SLiu Xiaodong #include "jsonrpc_internal.h"
8c10f8e16SLiu Xiaodong 
9c10f8e16SLiu Xiaodong static int
capture_version(const struct spdk_json_val * val,void * out)105d0f2620SPawel Wodkowski capture_version(const struct spdk_json_val *val, void *out)
11961a286aSPawel Wodkowski {
12961a286aSPawel Wodkowski 	const struct spdk_json_val **vptr = out;
13961a286aSPawel Wodkowski 
14961a286aSPawel Wodkowski 	if (spdk_json_strequal(val, "2.0") != true) {
15961a286aSPawel Wodkowski 		return SPDK_JSON_PARSE_INVALID;
16961a286aSPawel Wodkowski 	}
17961a286aSPawel Wodkowski 
18961a286aSPawel Wodkowski 	*vptr = val;
19961a286aSPawel Wodkowski 	return 0;
20961a286aSPawel Wodkowski }
21961a286aSPawel Wodkowski 
22961a286aSPawel Wodkowski static int
capture_id(const struct spdk_json_val * val,void * out)23961a286aSPawel Wodkowski capture_id(const struct spdk_json_val *val, void *out)
24961a286aSPawel Wodkowski {
25961a286aSPawel Wodkowski 	const struct spdk_json_val **vptr = out;
26961a286aSPawel Wodkowski 
27961a286aSPawel Wodkowski 	if (val->type != SPDK_JSON_VAL_STRING && val->type != SPDK_JSON_VAL_NUMBER) {
285d0f2620SPawel Wodkowski 		return -EINVAL;
29961a286aSPawel Wodkowski 	}
30961a286aSPawel Wodkowski 
31961a286aSPawel Wodkowski 	*vptr = val;
32961a286aSPawel Wodkowski 	return 0;
33961a286aSPawel Wodkowski }
34961a286aSPawel Wodkowski 
35961a286aSPawel Wodkowski static int
capture_any(const struct spdk_json_val * val,void * out)36961a286aSPawel Wodkowski capture_any(const struct spdk_json_val *val, void *out)
37c10f8e16SLiu Xiaodong {
38c10f8e16SLiu Xiaodong 	const struct spdk_json_val **vptr = out;
39c10f8e16SLiu Xiaodong 
40c10f8e16SLiu Xiaodong 	*vptr = val;
41c10f8e16SLiu Xiaodong 	return 0;
42c10f8e16SLiu Xiaodong }
43c10f8e16SLiu Xiaodong 
44c10f8e16SLiu Xiaodong static const struct spdk_json_object_decoder jsonrpc_response_decoders[] = {
455d0f2620SPawel Wodkowski 	{"jsonrpc", offsetof(struct spdk_jsonrpc_client_response, version), capture_version},
465d0f2620SPawel Wodkowski 	{"id", offsetof(struct spdk_jsonrpc_client_response, id), capture_id, true},
475d0f2620SPawel Wodkowski 	{"result", offsetof(struct spdk_jsonrpc_client_response, result), capture_any, true},
485d0f2620SPawel Wodkowski 	{"error", offsetof(struct spdk_jsonrpc_client_response, error), capture_any, true},
49c10f8e16SLiu Xiaodong };
50c10f8e16SLiu Xiaodong 
51c10f8e16SLiu Xiaodong int
jsonrpc_parse_response(struct spdk_jsonrpc_client * client)52134590a2SSeth Howell jsonrpc_parse_response(struct spdk_jsonrpc_client *client)
53c10f8e16SLiu Xiaodong {
545d0f2620SPawel Wodkowski 	struct spdk_jsonrpc_client_response_internal *r;
55c10f8e16SLiu Xiaodong 	ssize_t rc;
565d0f2620SPawel Wodkowski 	size_t buf_len;
575d0f2620SPawel Wodkowski 	size_t values_cnt;
58c10f8e16SLiu Xiaodong 	void *end = NULL;
59c10f8e16SLiu Xiaodong 
605d0f2620SPawel Wodkowski 
61c10f8e16SLiu Xiaodong 	/* Check to see if we have received a full JSON value. */
625d0f2620SPawel Wodkowski 	rc = spdk_json_parse(client->recv_buf, client->recv_offset, NULL, 0, &end, 0);
63c10f8e16SLiu Xiaodong 	if (rc == SPDK_JSON_PARSE_INCOMPLETE) {
647d38f166SPawel Wodkowski 		return 0;
65c10f8e16SLiu Xiaodong 	}
66c10f8e16SLiu Xiaodong 
672172c432STomasz Zawadzki 	SPDK_DEBUGLOG(rpc_client, "JSON string is :\n%s\n", client->recv_buf);
6892df9955SMichael Haeuptle 	if (rc < 0 || rc > SPDK_JSONRPC_CLIENT_MAX_VALUES) {
695d0f2620SPawel Wodkowski 		SPDK_ERRLOG("JSON parse error (rc: %zd)\n", rc);
70c10f8e16SLiu Xiaodong 		/*
71c10f8e16SLiu Xiaodong 		 * Can't recover from parse error (no guaranteed resync point in streaming JSON).
72c10f8e16SLiu Xiaodong 		 * Return an error to indicate that the connection should be closed.
73c10f8e16SLiu Xiaodong 		 */
745d0f2620SPawel Wodkowski 		return -EINVAL;
75c10f8e16SLiu Xiaodong 	}
76c10f8e16SLiu Xiaodong 
775d0f2620SPawel Wodkowski 	values_cnt = rc;
785d0f2620SPawel Wodkowski 
795d0f2620SPawel Wodkowski 	r = calloc(1, sizeof(*r) + sizeof(struct spdk_json_val) * (values_cnt + 1));
805d0f2620SPawel Wodkowski 	if (!r) {
815d0f2620SPawel Wodkowski 		return -errno;
825d0f2620SPawel Wodkowski 	}
835d0f2620SPawel Wodkowski 
845d0f2620SPawel Wodkowski 	if (client->resp) {
855d0f2620SPawel Wodkowski 		free(r);
865d0f2620SPawel Wodkowski 		return -ENOSPC;
875d0f2620SPawel Wodkowski 	}
885d0f2620SPawel Wodkowski 
895d0f2620SPawel Wodkowski 	client->resp = r;
905d0f2620SPawel Wodkowski 
915d0f2620SPawel Wodkowski 	r->buf = client->recv_buf;
925d0f2620SPawel Wodkowski 	buf_len = client->recv_offset;
935d0f2620SPawel Wodkowski 	r->values_cnt = values_cnt;
945d0f2620SPawel Wodkowski 
955d0f2620SPawel Wodkowski 	client->recv_buf_size = 0;
965d0f2620SPawel Wodkowski 	client->recv_offset = 0;
975d0f2620SPawel Wodkowski 	client->recv_buf = NULL;
985d0f2620SPawel Wodkowski 
99c10f8e16SLiu Xiaodong 	/* Decode a second time now that there is a full JSON value available. */
1005d0f2620SPawel Wodkowski 	rc = spdk_json_parse(r->buf, buf_len, r->values, values_cnt, &end,
101c10f8e16SLiu Xiaodong 			     SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE);
1025d0f2620SPawel Wodkowski 	if (rc != (ssize_t)values_cnt) {
1035d0f2620SPawel Wodkowski 		SPDK_ERRLOG("JSON parse error on second pass (rc: %zd, expected: %zu)\n", rc, values_cnt);
1045d0f2620SPawel Wodkowski 		goto err;
105c10f8e16SLiu Xiaodong 	}
106c10f8e16SLiu Xiaodong 
107c10f8e16SLiu Xiaodong 	assert(end != NULL);
108c10f8e16SLiu Xiaodong 
1095d0f2620SPawel Wodkowski 	if (r->values[0].type != SPDK_JSON_VAL_OBJECT_BEGIN) {
110c10f8e16SLiu Xiaodong 		SPDK_ERRLOG("top-level JSON value was not object\n");
1115d0f2620SPawel Wodkowski 		goto err;
112c10f8e16SLiu Xiaodong 	}
113c10f8e16SLiu Xiaodong 
1145d0f2620SPawel Wodkowski 	if (spdk_json_decode_object(r->values, jsonrpc_response_decoders,
1155d0f2620SPawel Wodkowski 				    SPDK_COUNTOF(jsonrpc_response_decoders), &r->jsonrpc)) {
1165d0f2620SPawel Wodkowski 		goto err;
1175d0f2620SPawel Wodkowski 	}
118c10f8e16SLiu Xiaodong 
1192f557958SPawel Wodkowski 	r->ready = 1;
1207d38f166SPawel Wodkowski 	return 1;
1215d0f2620SPawel Wodkowski 
1225d0f2620SPawel Wodkowski err:
1232f557958SPawel Wodkowski 	client->resp = NULL;
1245d0f2620SPawel Wodkowski 	spdk_jsonrpc_client_free_response(&r->jsonrpc);
1255d0f2620SPawel Wodkowski 	return -EINVAL;
126c10f8e16SLiu Xiaodong }
127c10f8e16SLiu Xiaodong 
128c10f8e16SLiu Xiaodong static int
jsonrpc_client_write_cb(void * cb_ctx,const void * data,size_t size)129c10f8e16SLiu Xiaodong jsonrpc_client_write_cb(void *cb_ctx, const void *data, size_t size)
130c10f8e16SLiu Xiaodong {
131c10f8e16SLiu Xiaodong 	struct spdk_jsonrpc_client_request *request = cb_ctx;
132c10f8e16SLiu Xiaodong 	size_t new_size = request->send_buf_size;
133c10f8e16SLiu Xiaodong 
134c10f8e16SLiu Xiaodong 	while (new_size - request->send_len < size) {
135c10f8e16SLiu Xiaodong 		if (new_size >= SPDK_JSONRPC_SEND_BUF_SIZE_MAX) {
136c10f8e16SLiu Xiaodong 			SPDK_ERRLOG("Send buf exceeded maximum size (%zu)\n",
137c10f8e16SLiu Xiaodong 				    (size_t)SPDK_JSONRPC_SEND_BUF_SIZE_MAX);
138c10f8e16SLiu Xiaodong 			return -ENOSPC;
139c10f8e16SLiu Xiaodong 		}
140c10f8e16SLiu Xiaodong 
141c10f8e16SLiu Xiaodong 		new_size *= 2;
142c10f8e16SLiu Xiaodong 	}
143c10f8e16SLiu Xiaodong 
144c10f8e16SLiu Xiaodong 	if (new_size != request->send_buf_size) {
145c10f8e16SLiu Xiaodong 		uint8_t *new_buf;
146c10f8e16SLiu Xiaodong 
147c10f8e16SLiu Xiaodong 		new_buf = realloc(request->send_buf, new_size);
148c10f8e16SLiu Xiaodong 		if (new_buf == NULL) {
149c10f8e16SLiu Xiaodong 			SPDK_ERRLOG("Resizing send_buf failed (current size %zu, new size %zu)\n",
150c10f8e16SLiu Xiaodong 				    request->send_buf_size, new_size);
151c10f8e16SLiu Xiaodong 			return -ENOMEM;
152c10f8e16SLiu Xiaodong 		}
153c10f8e16SLiu Xiaodong 
154c10f8e16SLiu Xiaodong 		request->send_buf = new_buf;
155c10f8e16SLiu Xiaodong 		request->send_buf_size = new_size;
156c10f8e16SLiu Xiaodong 	}
157c10f8e16SLiu Xiaodong 
158c10f8e16SLiu Xiaodong 	memcpy(request->send_buf + request->send_len, data, size);
159c10f8e16SLiu Xiaodong 	request->send_len += size;
160c10f8e16SLiu Xiaodong 
161c10f8e16SLiu Xiaodong 	return 0;
162c10f8e16SLiu Xiaodong }
163c10f8e16SLiu Xiaodong 
164c10f8e16SLiu Xiaodong struct spdk_json_write_ctx *
spdk_jsonrpc_begin_request(struct spdk_jsonrpc_client_request * request,int32_t id,const char * method)1658397285bSPawel Wodkowski spdk_jsonrpc_begin_request(struct spdk_jsonrpc_client_request *request, int32_t id,
1668397285bSPawel Wodkowski 			   const char *method)
167c10f8e16SLiu Xiaodong {
168c10f8e16SLiu Xiaodong 	struct spdk_json_write_ctx *w;
169c10f8e16SLiu Xiaodong 
170c10f8e16SLiu Xiaodong 	w = spdk_json_write_begin(jsonrpc_client_write_cb, request, 0);
171c10f8e16SLiu Xiaodong 	if (w == NULL) {
172c10f8e16SLiu Xiaodong 		return NULL;
173c10f8e16SLiu Xiaodong 	}
174c10f8e16SLiu Xiaodong 
175c10f8e16SLiu Xiaodong 	spdk_json_write_object_begin(w);
176c10f8e16SLiu Xiaodong 	spdk_json_write_named_string(w, "jsonrpc", "2.0");
1778397285bSPawel Wodkowski 
1788397285bSPawel Wodkowski 	if (id >= 0) {
179c10f8e16SLiu Xiaodong 		spdk_json_write_named_int32(w, "id", id);
1808397285bSPawel Wodkowski 	}
1818397285bSPawel Wodkowski 
1828397285bSPawel Wodkowski 	if (method) {
183c10f8e16SLiu Xiaodong 		spdk_json_write_named_string(w, "method", method);
1848397285bSPawel Wodkowski 	}
185c10f8e16SLiu Xiaodong 
186c10f8e16SLiu Xiaodong 	return w;
187c10f8e16SLiu Xiaodong }
188c10f8e16SLiu Xiaodong 
189c10f8e16SLiu Xiaodong void
spdk_jsonrpc_end_request(struct spdk_jsonrpc_client_request * request,struct spdk_json_write_ctx * w)190c10f8e16SLiu Xiaodong spdk_jsonrpc_end_request(struct spdk_jsonrpc_client_request *request, struct spdk_json_write_ctx *w)
191c10f8e16SLiu Xiaodong {
192c10f8e16SLiu Xiaodong 	assert(w != NULL);
193c10f8e16SLiu Xiaodong 
194c10f8e16SLiu Xiaodong 	spdk_json_write_object_end(w);
195c10f8e16SLiu Xiaodong 	spdk_json_write_end(w);
196c10f8e16SLiu Xiaodong 	jsonrpc_client_write_cb(request, "\n", 1);
197c10f8e16SLiu Xiaodong }
198c10f8e16SLiu Xiaodong 
1992172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(rpc_client)
200