1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause
2a4009e7aSShuhei Matsumoto * Copyright (C) 2016 Intel Corporation. All rights reserved.
3a4009e7aSShuhei Matsumoto * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4376d117cSDaniel Verkamp */
5376d117cSDaniel Verkamp
6376d117cSDaniel Verkamp #include "jsonrpc_internal.h"
7376d117cSDaniel Verkamp
8b58a5d73SDaniel Verkamp #include "spdk/util.h"
9b58a5d73SDaniel Verkamp
10a4009e7aSShuhei Matsumoto static enum spdk_log_level g_rpc_log_level = SPDK_LOG_DISABLED;
11a4009e7aSShuhei Matsumoto static FILE *g_rpc_log_file = NULL;
12a4009e7aSShuhei Matsumoto
13376d117cSDaniel Verkamp struct jsonrpc_request {
14376d117cSDaniel Verkamp const struct spdk_json_val *version;
15376d117cSDaniel Verkamp const struct spdk_json_val *method;
16376d117cSDaniel Verkamp const struct spdk_json_val *params;
17376d117cSDaniel Verkamp const struct spdk_json_val *id;
18376d117cSDaniel Verkamp };
19376d117cSDaniel Verkamp
20a4009e7aSShuhei Matsumoto void
spdk_jsonrpc_set_log_level(enum spdk_log_level level)21a4009e7aSShuhei Matsumoto spdk_jsonrpc_set_log_level(enum spdk_log_level level)
22a4009e7aSShuhei Matsumoto {
23a4009e7aSShuhei Matsumoto assert(level >= SPDK_LOG_DISABLED);
24a4009e7aSShuhei Matsumoto assert(level <= SPDK_LOG_DEBUG);
25a4009e7aSShuhei Matsumoto g_rpc_log_level = level;
26a4009e7aSShuhei Matsumoto }
27a4009e7aSShuhei Matsumoto
28a4009e7aSShuhei Matsumoto void
spdk_jsonrpc_set_log_file(FILE * file)29a4009e7aSShuhei Matsumoto spdk_jsonrpc_set_log_file(FILE *file)
30a4009e7aSShuhei Matsumoto {
31a4009e7aSShuhei Matsumoto g_rpc_log_file = file;
32a4009e7aSShuhei Matsumoto }
33a4009e7aSShuhei Matsumoto
34a4009e7aSShuhei Matsumoto static void
remove_newlines(char * text)35a4009e7aSShuhei Matsumoto remove_newlines(char *text)
36a4009e7aSShuhei Matsumoto {
37a4009e7aSShuhei Matsumoto int i = 0, j = 0;
38a4009e7aSShuhei Matsumoto
39a4009e7aSShuhei Matsumoto while (text[i] != '\0') {
40a4009e7aSShuhei Matsumoto if (text[i] != '\n') {
41a4009e7aSShuhei Matsumoto text[j++] = text[i];
42a4009e7aSShuhei Matsumoto }
43a4009e7aSShuhei Matsumoto i++;
44a4009e7aSShuhei Matsumoto }
45a4009e7aSShuhei Matsumoto text[j] = '\0';
46a4009e7aSShuhei Matsumoto }
47a4009e7aSShuhei Matsumoto
48a4009e7aSShuhei Matsumoto static void
jsonrpc_log(char * buf,const char * prefix)49a4009e7aSShuhei Matsumoto jsonrpc_log(char *buf, const char *prefix)
50a4009e7aSShuhei Matsumoto {
51*1078198eSShuhei Matsumoto /* Some custom applications have enabled SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS
52*1078198eSShuhei Matsumoto * to allow comments in JSON RPC objects. To keep backward compatibility of
53*1078198eSShuhei Matsumoto * these applications, remove newlines only if JSON RPC logging is enabled.
54a4009e7aSShuhei Matsumoto */
55*1078198eSShuhei Matsumoto if (g_rpc_log_level != SPDK_LOG_DISABLED || g_rpc_log_file != NULL) {
56a4009e7aSShuhei Matsumoto remove_newlines(buf);
57*1078198eSShuhei Matsumoto }
58a4009e7aSShuhei Matsumoto
59a4009e7aSShuhei Matsumoto if (g_rpc_log_level != SPDK_LOG_DISABLED) {
60a4009e7aSShuhei Matsumoto spdk_log(g_rpc_log_level, NULL, 0, NULL, "%s%s\n", prefix, buf);
61a4009e7aSShuhei Matsumoto }
62a4009e7aSShuhei Matsumoto
63a4009e7aSShuhei Matsumoto if (g_rpc_log_file != NULL) {
64a4009e7aSShuhei Matsumoto spdk_flog(g_rpc_log_file, NULL, 0, NULL, "%s%s\n", prefix, buf);
65a4009e7aSShuhei Matsumoto }
66a4009e7aSShuhei Matsumoto }
67a4009e7aSShuhei Matsumoto
68376d117cSDaniel Verkamp static int
capture_val(const struct spdk_json_val * val,void * out)69376d117cSDaniel Verkamp capture_val(const struct spdk_json_val *val, void *out)
70376d117cSDaniel Verkamp {
71376d117cSDaniel Verkamp const struct spdk_json_val **vptr = out;
72376d117cSDaniel Verkamp
73376d117cSDaniel Verkamp *vptr = val;
74376d117cSDaniel Verkamp return 0;
75376d117cSDaniel Verkamp }
76376d117cSDaniel Verkamp
77376d117cSDaniel Verkamp static const struct spdk_json_object_decoder jsonrpc_request_decoders[] = {
78da7673f7SDaniel Verkamp {"jsonrpc", offsetof(struct jsonrpc_request, version), capture_val, true},
79376d117cSDaniel Verkamp {"method", offsetof(struct jsonrpc_request, method), capture_val},
80376d117cSDaniel Verkamp {"params", offsetof(struct jsonrpc_request, params), capture_val, true},
81376d117cSDaniel Verkamp {"id", offsetof(struct jsonrpc_request, id), capture_val, true},
82376d117cSDaniel Verkamp };
83376d117cSDaniel Verkamp
84376d117cSDaniel Verkamp static void
parse_single_request(struct spdk_jsonrpc_request * request,struct spdk_json_val * values)85977fd230SDaniel Verkamp parse_single_request(struct spdk_jsonrpc_request *request, struct spdk_json_val *values)
86376d117cSDaniel Verkamp {
87376d117cSDaniel Verkamp struct jsonrpc_request req = {};
8859339feaSJan Kryl const struct spdk_json_val *params = NULL;
89376d117cSDaniel Verkamp
90376d117cSDaniel Verkamp if (spdk_json_decode_object(values, jsonrpc_request_decoders,
91b58a5d73SDaniel Verkamp SPDK_COUNTOF(jsonrpc_request_decoders),
92376d117cSDaniel Verkamp &req)) {
9363978010SPawel Wodkowski goto invalid;
94376d117cSDaniel Verkamp }
95376d117cSDaniel Verkamp
96aa67900aSDaniel Verkamp if (req.version && (req.version->type != SPDK_JSON_VAL_STRING ||
97aa67900aSDaniel Verkamp !spdk_json_strequal(req.version, "2.0"))) {
9863978010SPawel Wodkowski goto invalid;
99376d117cSDaniel Verkamp }
100376d117cSDaniel Verkamp
101376d117cSDaniel Verkamp if (!req.method || req.method->type != SPDK_JSON_VAL_STRING) {
10263978010SPawel Wodkowski goto invalid;
103376d117cSDaniel Verkamp }
104376d117cSDaniel Verkamp
105376d117cSDaniel Verkamp if (req.id) {
106977fd230SDaniel Verkamp if (req.id->type == SPDK_JSON_VAL_STRING ||
10763978010SPawel Wodkowski req.id->type == SPDK_JSON_VAL_NUMBER ||
10863978010SPawel Wodkowski req.id->type == SPDK_JSON_VAL_NULL) {
10963978010SPawel Wodkowski request->id = req.id;
1102bdec64fSDaniel Verkamp } else {
11163978010SPawel Wodkowski goto invalid;
112376d117cSDaniel Verkamp }
113376d117cSDaniel Verkamp }
114376d117cSDaniel Verkamp
115376d117cSDaniel Verkamp if (req.params) {
11659339feaSJan Kryl /* null json value is as if there were no parameters */
11759339feaSJan Kryl if (req.params->type != SPDK_JSON_VAL_NULL) {
118376d117cSDaniel Verkamp if (req.params->type != SPDK_JSON_VAL_ARRAY_BEGIN &&
119376d117cSDaniel Verkamp req.params->type != SPDK_JSON_VAL_OBJECT_BEGIN) {
12063978010SPawel Wodkowski goto invalid;
121376d117cSDaniel Verkamp }
12259339feaSJan Kryl params = req.params;
12359339feaSJan Kryl }
124376d117cSDaniel Verkamp }
125376d117cSDaniel Verkamp
126134590a2SSeth Howell jsonrpc_server_handle_request(request, req.method, params);
12763978010SPawel Wodkowski return;
12863978010SPawel Wodkowski
12963978010SPawel Wodkowski invalid:
130134590a2SSeth Howell jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
131376d117cSDaniel Verkamp }
132376d117cSDaniel Verkamp
133d270cd36SPawel Kaminski static int
jsonrpc_server_write_cb(void * cb_ctx,const void * data,size_t size)1340be5557cSSeth Howell jsonrpc_server_write_cb(void *cb_ctx, const void *data, size_t size)
135d270cd36SPawel Kaminski {
136d270cd36SPawel Kaminski struct spdk_jsonrpc_request *request = cb_ctx;
137d270cd36SPawel Kaminski size_t new_size = request->send_buf_size;
138d270cd36SPawel Kaminski
139d270cd36SPawel Kaminski while (new_size - request->send_len < size) {
140d270cd36SPawel Kaminski if (new_size >= SPDK_JSONRPC_SEND_BUF_SIZE_MAX) {
141d270cd36SPawel Kaminski SPDK_ERRLOG("Send buf exceeded maximum size (%zu)\n",
142d270cd36SPawel Kaminski (size_t)SPDK_JSONRPC_SEND_BUF_SIZE_MAX);
143d270cd36SPawel Kaminski return -1;
144d270cd36SPawel Kaminski }
145d270cd36SPawel Kaminski
146d270cd36SPawel Kaminski new_size *= 2;
147d270cd36SPawel Kaminski }
148d270cd36SPawel Kaminski
149d270cd36SPawel Kaminski if (new_size != request->send_buf_size) {
150d270cd36SPawel Kaminski uint8_t *new_buf;
151d270cd36SPawel Kaminski
15230b534c9SShuhei Matsumoto /* Add extra byte for the null terminator. */
15330b534c9SShuhei Matsumoto new_buf = realloc(request->send_buf, new_size + 1);
154d270cd36SPawel Kaminski if (new_buf == NULL) {
155d270cd36SPawel Kaminski SPDK_ERRLOG("Resizing send_buf failed (current size %zu, new size %zu)\n",
156d270cd36SPawel Kaminski request->send_buf_size, new_size);
157d270cd36SPawel Kaminski return -1;
158d270cd36SPawel Kaminski }
159d270cd36SPawel Kaminski
160d270cd36SPawel Kaminski request->send_buf = new_buf;
161d270cd36SPawel Kaminski request->send_buf_size = new_size;
162d270cd36SPawel Kaminski }
163d270cd36SPawel Kaminski
164d270cd36SPawel Kaminski memcpy(request->send_buf + request->send_len, data, size);
165d270cd36SPawel Kaminski request->send_len += size;
166d270cd36SPawel Kaminski
167d270cd36SPawel Kaminski return 0;
168d270cd36SPawel Kaminski }
169d270cd36SPawel Kaminski
170376d117cSDaniel Verkamp int
jsonrpc_parse_request(struct spdk_jsonrpc_server_conn * conn,const void * json,size_t size)171134590a2SSeth Howell jsonrpc_parse_request(struct spdk_jsonrpc_server_conn *conn, const void *json, size_t size)
172376d117cSDaniel Verkamp {
173977fd230SDaniel Verkamp struct spdk_jsonrpc_request *request;
174376d117cSDaniel Verkamp ssize_t rc;
17563978010SPawel Wodkowski size_t len;
176376d117cSDaniel Verkamp void *end = NULL;
177376d117cSDaniel Verkamp
17863978010SPawel Wodkowski /* Check to see if we have received a full JSON value. It is safe to cast away const
17963978010SPawel Wodkowski * as we don't decode in place. */
18063978010SPawel Wodkowski rc = spdk_json_parse((void *)json, size, NULL, 0, &end, 0);
181376d117cSDaniel Verkamp if (rc == SPDK_JSON_PARSE_INCOMPLETE) {
182376d117cSDaniel Verkamp return 0;
183977fd230SDaniel Verkamp }
184977fd230SDaniel Verkamp
185977fd230SDaniel Verkamp request = calloc(1, sizeof(*request));
186977fd230SDaniel Verkamp if (request == NULL) {
1872172c432STomasz Zawadzki SPDK_DEBUGLOG(rpc, "Out of memory allocating request\n");
188977fd230SDaniel Verkamp return -1;
189977fd230SDaniel Verkamp }
190977fd230SDaniel Verkamp
1912fb672afSKrzysztof Karas pthread_spin_lock(&conn->queue_lock);
1924e003b67SDaniel Verkamp conn->outstanding_requests++;
1932fb672afSKrzysztof Karas STAILQ_INSERT_TAIL(&conn->outstanding_queue, request, link);
1942fb672afSKrzysztof Karas pthread_spin_unlock(&conn->queue_lock);
1954e003b67SDaniel Verkamp
196977fd230SDaniel Verkamp request->conn = conn;
19763978010SPawel Wodkowski
19863978010SPawel Wodkowski len = end - json;
19963978010SPawel Wodkowski request->recv_buffer = malloc(len + 1);
20063978010SPawel Wodkowski if (request->recv_buffer == NULL) {
20163978010SPawel Wodkowski SPDK_ERRLOG("Failed to allocate buffer to copy request (%zu bytes)\n", len + 1);
202134590a2SSeth Howell jsonrpc_free_request(request);
20363978010SPawel Wodkowski return -1;
20463978010SPawel Wodkowski }
20563978010SPawel Wodkowski
20663978010SPawel Wodkowski memcpy(request->recv_buffer, json, len);
20763978010SPawel Wodkowski request->recv_buffer[len] = '\0';
20863978010SPawel Wodkowski
209a4009e7aSShuhei Matsumoto jsonrpc_log(request->recv_buffer, "request: ");
210a4009e7aSShuhei Matsumoto
21163978010SPawel Wodkowski if (rc > 0 && rc <= SPDK_JSONRPC_MAX_VALUES) {
21263978010SPawel Wodkowski request->values_cnt = rc;
21363978010SPawel Wodkowski request->values = malloc(request->values_cnt * sizeof(request->values[0]));
21463978010SPawel Wodkowski if (request->values == NULL) {
21563978010SPawel Wodkowski SPDK_ERRLOG("Failed to allocate buffer for JSON values (%zu bytes)\n",
21663978010SPawel Wodkowski request->values_cnt * sizeof(request->values[0]));
217134590a2SSeth Howell jsonrpc_free_request(request);
21863978010SPawel Wodkowski return -1;
21963978010SPawel Wodkowski }
22063978010SPawel Wodkowski }
22163978010SPawel Wodkowski
2224e003b67SDaniel Verkamp request->send_offset = 0;
2234e003b67SDaniel Verkamp request->send_len = 0;
224c7852cf9SDaniel Verkamp request->send_buf_size = SPDK_JSONRPC_SEND_BUF_SIZE_INIT;
22530b534c9SShuhei Matsumoto /* Add extra byte for the null terminator. */
22630b534c9SShuhei Matsumoto request->send_buf = malloc(request->send_buf_size + 1);
227c7852cf9SDaniel Verkamp if (request->send_buf == NULL) {
228c7852cf9SDaniel Verkamp SPDK_ERRLOG("Failed to allocate send_buf (%zu bytes)\n", request->send_buf_size);
229134590a2SSeth Howell jsonrpc_free_request(request);
230c7852cf9SDaniel Verkamp return -1;
231c7852cf9SDaniel Verkamp }
232977fd230SDaniel Verkamp
2330be5557cSSeth Howell request->response = spdk_json_write_begin(jsonrpc_server_write_cb, request, 0);
234a15dcb0bSPawel Kaminski if (request->response == NULL) {
235a15dcb0bSPawel Kaminski SPDK_ERRLOG("Failed to allocate response JSON write context.\n");
236134590a2SSeth Howell jsonrpc_free_request(request);
237a15dcb0bSPawel Kaminski return -1;
238a15dcb0bSPawel Kaminski }
239a15dcb0bSPawel Kaminski
24063978010SPawel Wodkowski if (rc <= 0 || rc > SPDK_JSONRPC_MAX_VALUES) {
2412172c432STomasz Zawadzki SPDK_DEBUGLOG(rpc, "JSON parse error\n");
242134590a2SSeth Howell jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_PARSE_ERROR);
243376d117cSDaniel Verkamp
244376d117cSDaniel Verkamp /*
245376d117cSDaniel Verkamp * Can't recover from parse error (no guaranteed resync point in streaming JSON).
246376d117cSDaniel Verkamp * Return an error to indicate that the connection should be closed.
247376d117cSDaniel Verkamp */
248376d117cSDaniel Verkamp return -1;
249376d117cSDaniel Verkamp }
250376d117cSDaniel Verkamp
251376d117cSDaniel Verkamp /* Decode a second time now that there is a full JSON value available. */
25263978010SPawel Wodkowski rc = spdk_json_parse(request->recv_buffer, size, request->values, request->values_cnt, &end,
253376d117cSDaniel Verkamp SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE);
254376d117cSDaniel Verkamp if (rc < 0 || rc > SPDK_JSONRPC_MAX_VALUES) {
2552172c432STomasz Zawadzki SPDK_DEBUGLOG(rpc, "JSON parse error on second pass\n");
256134590a2SSeth Howell jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_PARSE_ERROR);
257376d117cSDaniel Verkamp return -1;
258376d117cSDaniel Verkamp }
259376d117cSDaniel Verkamp
260376d117cSDaniel Verkamp assert(end != NULL);
261376d117cSDaniel Verkamp
26263978010SPawel Wodkowski if (request->values[0].type == SPDK_JSON_VAL_OBJECT_BEGIN) {
26363978010SPawel Wodkowski parse_single_request(request, request->values);
26463978010SPawel Wodkowski } else if (request->values[0].type == SPDK_JSON_VAL_ARRAY_BEGIN) {
2652172c432STomasz Zawadzki SPDK_DEBUGLOG(rpc, "Got batch array (not currently supported)\n");
266134590a2SSeth Howell jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
267376d117cSDaniel Verkamp } else {
2682172c432STomasz Zawadzki SPDK_DEBUGLOG(rpc, "top-level JSON value was not array or object\n");
269134590a2SSeth Howell jsonrpc_server_handle_error(request, SPDK_JSONRPC_ERROR_INVALID_REQUEST);
270376d117cSDaniel Verkamp }
271376d117cSDaniel Verkamp
27263978010SPawel Wodkowski return len;
273376d117cSDaniel Verkamp }
274376d117cSDaniel Verkamp
2755b1b3ddfSPawel Wodkowski struct spdk_jsonrpc_server_conn *
spdk_jsonrpc_get_conn(struct spdk_jsonrpc_request * request)2765b1b3ddfSPawel Wodkowski spdk_jsonrpc_get_conn(struct spdk_jsonrpc_request *request)
2775b1b3ddfSPawel Wodkowski {
2785b1b3ddfSPawel Wodkowski return request->conn;
2795b1b3ddfSPawel Wodkowski }
2805b1b3ddfSPawel Wodkowski
281a15dcb0bSPawel Kaminski /* Never return NULL */
282376d117cSDaniel Verkamp static struct spdk_json_write_ctx *
begin_response(struct spdk_jsonrpc_request * request)2834e003b67SDaniel Verkamp begin_response(struct spdk_jsonrpc_request *request)
284376d117cSDaniel Verkamp {
285a15dcb0bSPawel Kaminski struct spdk_json_write_ctx *w = request->response;
286376d117cSDaniel Verkamp
287376d117cSDaniel Verkamp spdk_json_write_object_begin(w);
28873f79a5cSShuhei Matsumoto spdk_json_write_named_string(w, "jsonrpc", "2.0");
289376d117cSDaniel Verkamp
290376d117cSDaniel Verkamp spdk_json_write_name(w, "id");
29163978010SPawel Wodkowski if (request->id) {
29263978010SPawel Wodkowski spdk_json_write_val(w, request->id);
29363978010SPawel Wodkowski } else {
29463978010SPawel Wodkowski spdk_json_write_null(w);
29563978010SPawel Wodkowski }
296376d117cSDaniel Verkamp
297376d117cSDaniel Verkamp return w;
298376d117cSDaniel Verkamp }
299376d117cSDaniel Verkamp
300376d117cSDaniel Verkamp static void
skip_response(struct spdk_jsonrpc_request * request)3010f842e86SPawel Wodkowski skip_response(struct spdk_jsonrpc_request *request)
3020f842e86SPawel Wodkowski {
3030f842e86SPawel Wodkowski request->send_len = 0;
304a15dcb0bSPawel Kaminski spdk_json_write_end(request->response);
305a15dcb0bSPawel Kaminski request->response = NULL;
306134590a2SSeth Howell jsonrpc_server_send_response(request);
3070f842e86SPawel Wodkowski }
3080f842e86SPawel Wodkowski
3090f842e86SPawel Wodkowski static void
end_response(struct spdk_jsonrpc_request * request)310a15dcb0bSPawel Kaminski end_response(struct spdk_jsonrpc_request *request)
311376d117cSDaniel Verkamp {
312a15dcb0bSPawel Kaminski spdk_json_write_object_end(request->response);
313a15dcb0bSPawel Kaminski spdk_json_write_end(request->response);
314a15dcb0bSPawel Kaminski request->response = NULL;
315a15dcb0bSPawel Kaminski
3160be5557cSSeth Howell jsonrpc_server_write_cb(request, "\n", 1);
317134590a2SSeth Howell jsonrpc_server_send_response(request);
3184e003b67SDaniel Verkamp }
3194e003b67SDaniel Verkamp
3204e003b67SDaniel Verkamp void
jsonrpc_free_request(struct spdk_jsonrpc_request * request)321134590a2SSeth Howell jsonrpc_free_request(struct spdk_jsonrpc_request *request)
3224e003b67SDaniel Verkamp {
3232fb672afSKrzysztof Karas struct spdk_jsonrpc_request *req;
3242fb672afSKrzysztof Karas struct spdk_jsonrpc_server_conn *conn;
3252fb672afSKrzysztof Karas
32663978010SPawel Wodkowski if (!request) {
32763978010SPawel Wodkowski return;
32863978010SPawel Wodkowski }
32963978010SPawel Wodkowski
330a15dcb0bSPawel Kaminski /* We must send or skip response explicitly */
331a15dcb0bSPawel Kaminski assert(request->response == NULL);
332a15dcb0bSPawel Kaminski
3332fb672afSKrzysztof Karas conn = request->conn;
3342fb672afSKrzysztof Karas if (conn != NULL) {
3352fb672afSKrzysztof Karas pthread_spin_lock(&conn->queue_lock);
3362fb672afSKrzysztof Karas conn->outstanding_requests--;
3372fb672afSKrzysztof Karas STAILQ_FOREACH(req, &conn->outstanding_queue, link) {
3382fb672afSKrzysztof Karas if (req == request) {
3392fb672afSKrzysztof Karas STAILQ_REMOVE(&conn->outstanding_queue,
3402fb672afSKrzysztof Karas req, spdk_jsonrpc_request, link);
3412fb672afSKrzysztof Karas break;
3422fb672afSKrzysztof Karas }
3432fb672afSKrzysztof Karas }
3442fb672afSKrzysztof Karas pthread_spin_unlock(&conn->queue_lock);
3452fb672afSKrzysztof Karas }
34663978010SPawel Wodkowski free(request->recv_buffer);
34763978010SPawel Wodkowski free(request->values);
348c7852cf9SDaniel Verkamp free(request->send_buf);
3494e003b67SDaniel Verkamp free(request);
350376d117cSDaniel Verkamp }
351376d117cSDaniel Verkamp
352b3bec079SShuhei Matsumoto void
jsonrpc_complete_request(struct spdk_jsonrpc_request * request)353b3bec079SShuhei Matsumoto jsonrpc_complete_request(struct spdk_jsonrpc_request *request)
354b3bec079SShuhei Matsumoto {
355a4009e7aSShuhei Matsumoto jsonrpc_log(request->send_buf, "response: ");
356a4009e7aSShuhei Matsumoto
357b3bec079SShuhei Matsumoto jsonrpc_free_request(request);
358b3bec079SShuhei Matsumoto }
359b3bec079SShuhei Matsumoto
360376d117cSDaniel Verkamp struct spdk_json_write_ctx *
spdk_jsonrpc_begin_result(struct spdk_jsonrpc_request * request)3612bdec64fSDaniel Verkamp spdk_jsonrpc_begin_result(struct spdk_jsonrpc_request *request)
362376d117cSDaniel Verkamp {
363a15dcb0bSPawel Kaminski struct spdk_json_write_ctx *w = begin_response(request);
364376d117cSDaniel Verkamp
365376d117cSDaniel Verkamp spdk_json_write_name(w, "result");
366376d117cSDaniel Verkamp return w;
367376d117cSDaniel Verkamp }
368376d117cSDaniel Verkamp
369376d117cSDaniel Verkamp void
spdk_jsonrpc_end_result(struct spdk_jsonrpc_request * request,struct spdk_json_write_ctx * w)3702bdec64fSDaniel Verkamp spdk_jsonrpc_end_result(struct spdk_jsonrpc_request *request, struct spdk_json_write_ctx *w)
371376d117cSDaniel Verkamp {
372376d117cSDaniel Verkamp assert(w != NULL);
373a15dcb0bSPawel Kaminski assert(w == request->response);
374376d117cSDaniel Verkamp
375a15dcb0bSPawel Kaminski /* If there was no ID in request we skip response. */
376a15dcb0bSPawel Kaminski if (request->id && request->id->type != SPDK_JSON_VAL_NULL) {
377a15dcb0bSPawel Kaminski end_response(request);
378a15dcb0bSPawel Kaminski } else {
379a15dcb0bSPawel Kaminski skip_response(request);
380a15dcb0bSPawel Kaminski }
381376d117cSDaniel Verkamp }
382376d117cSDaniel Verkamp
383376d117cSDaniel Verkamp void
spdk_jsonrpc_send_bool_response(struct spdk_jsonrpc_request * request,bool value)384d73077b8Syidong0635 spdk_jsonrpc_send_bool_response(struct spdk_jsonrpc_request *request, bool value)
385d73077b8Syidong0635 {
386d73077b8Syidong0635 struct spdk_json_write_ctx *w;
387d73077b8Syidong0635
388d73077b8Syidong0635 w = spdk_jsonrpc_begin_result(request);
389d73077b8Syidong0635 assert(w != NULL);
390d73077b8Syidong0635 spdk_json_write_bool(w, value);
391d73077b8Syidong0635 spdk_jsonrpc_end_result(request, w);
392d73077b8Syidong0635 }
393d73077b8Syidong0635
394d73077b8Syidong0635 void
spdk_jsonrpc_send_error_response(struct spdk_jsonrpc_request * request,int error_code,const char * msg)3952bdec64fSDaniel Verkamp spdk_jsonrpc_send_error_response(struct spdk_jsonrpc_request *request,
396376d117cSDaniel Verkamp int error_code, const char *msg)
397376d117cSDaniel Verkamp {
398a15dcb0bSPawel Kaminski struct spdk_json_write_ctx *w = begin_response(request);
399376d117cSDaniel Verkamp
40073f79a5cSShuhei Matsumoto spdk_json_write_named_object_begin(w, "error");
40173f79a5cSShuhei Matsumoto spdk_json_write_named_int32(w, "code", error_code);
40273f79a5cSShuhei Matsumoto spdk_json_write_named_string(w, "message", msg);
403376d117cSDaniel Verkamp spdk_json_write_object_end(w);
404376d117cSDaniel Verkamp
405a15dcb0bSPawel Kaminski end_response(request);
406376d117cSDaniel Verkamp }
407376d117cSDaniel Verkamp
40897cb1713SPawel Wodkowski void
spdk_jsonrpc_send_error_response_fmt(struct spdk_jsonrpc_request * request,int error_code,const char * fmt,...)40997cb1713SPawel Wodkowski spdk_jsonrpc_send_error_response_fmt(struct spdk_jsonrpc_request *request,
41097cb1713SPawel Wodkowski int error_code, const char *fmt, ...)
41197cb1713SPawel Wodkowski {
412a15dcb0bSPawel Kaminski struct spdk_json_write_ctx *w = begin_response(request);
41397cb1713SPawel Wodkowski va_list args;
41497cb1713SPawel Wodkowski
41573f79a5cSShuhei Matsumoto spdk_json_write_named_object_begin(w, "error");
41673f79a5cSShuhei Matsumoto spdk_json_write_named_int32(w, "code", error_code);
41797cb1713SPawel Wodkowski va_start(args, fmt);
41873f79a5cSShuhei Matsumoto spdk_json_write_named_string_fmt_v(w, "message", fmt, args);
41997cb1713SPawel Wodkowski va_end(args);
42097cb1713SPawel Wodkowski spdk_json_write_object_end(w);
42197cb1713SPawel Wodkowski
422a15dcb0bSPawel Kaminski end_response(request);
42397cb1713SPawel Wodkowski }
42497cb1713SPawel Wodkowski
4252172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(rpc)
426