]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright (c) Intel Corporation. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * * Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * * Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * * Neither the name of Intel Corporation nor the names of its | |
18 | * contributors may be used to endorse or promote products derived | |
19 | * from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
25 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #include "spdk/util.h" | |
35 | #include "jsonrpc_internal.h" | |
36 | ||
11fdf7f2 | 37 | static int |
9f95a23c | 38 | capture_version(const struct spdk_json_val *val, void *out) |
11fdf7f2 TL |
39 | { |
40 | const struct spdk_json_val **vptr = out; | |
41 | ||
42 | if (spdk_json_strequal(val, "2.0") != true) { | |
43 | return SPDK_JSON_PARSE_INVALID; | |
44 | } | |
45 | ||
46 | *vptr = val; | |
47 | return 0; | |
48 | } | |
49 | ||
50 | static int | |
51 | capture_id(const struct spdk_json_val *val, void *out) | |
52 | { | |
53 | const struct spdk_json_val **vptr = out; | |
54 | ||
55 | if (val->type != SPDK_JSON_VAL_STRING && val->type != SPDK_JSON_VAL_NUMBER) { | |
9f95a23c | 56 | return -EINVAL; |
11fdf7f2 TL |
57 | } |
58 | ||
59 | *vptr = val; | |
60 | return 0; | |
61 | } | |
62 | ||
63 | static int | |
64 | capture_any(const struct spdk_json_val *val, void *out) | |
65 | { | |
66 | const struct spdk_json_val **vptr = out; | |
67 | ||
68 | *vptr = val; | |
69 | return 0; | |
70 | } | |
71 | ||
72 | static const struct spdk_json_object_decoder jsonrpc_response_decoders[] = { | |
9f95a23c TL |
73 | {"jsonrpc", offsetof(struct spdk_jsonrpc_client_response, version), capture_version}, |
74 | {"id", offsetof(struct spdk_jsonrpc_client_response, id), capture_id, true}, | |
75 | {"result", offsetof(struct spdk_jsonrpc_client_response, result), capture_any, true}, | |
76 | {"error", offsetof(struct spdk_jsonrpc_client_response, error), capture_any, true}, | |
11fdf7f2 TL |
77 | }; |
78 | ||
11fdf7f2 | 79 | int |
9f95a23c | 80 | spdk_jsonrpc_parse_response(struct spdk_jsonrpc_client *client) |
11fdf7f2 | 81 | { |
9f95a23c | 82 | struct spdk_jsonrpc_client_response_internal *r; |
11fdf7f2 | 83 | ssize_t rc; |
9f95a23c TL |
84 | size_t buf_len; |
85 | size_t values_cnt; | |
11fdf7f2 TL |
86 | void *end = NULL; |
87 | ||
9f95a23c | 88 | |
11fdf7f2 | 89 | /* Check to see if we have received a full JSON value. */ |
9f95a23c | 90 | rc = spdk_json_parse(client->recv_buf, client->recv_offset, NULL, 0, &end, 0); |
11fdf7f2 | 91 | if (rc == SPDK_JSON_PARSE_INCOMPLETE) { |
9f95a23c | 92 | return 0; |
11fdf7f2 TL |
93 | } |
94 | ||
9f95a23c | 95 | SPDK_DEBUGLOG(SPDK_LOG_RPC_CLIENT, "JSON string is :\n%s\n", client->recv_buf); |
11fdf7f2 | 96 | if (rc < 0 || rc > SPDK_JSONRPC_MAX_VALUES) { |
9f95a23c | 97 | SPDK_ERRLOG("JSON parse error (rc: %zd)\n", rc); |
11fdf7f2 TL |
98 | /* |
99 | * Can't recover from parse error (no guaranteed resync point in streaming JSON). | |
100 | * Return an error to indicate that the connection should be closed. | |
101 | */ | |
9f95a23c | 102 | return -EINVAL; |
11fdf7f2 TL |
103 | } |
104 | ||
9f95a23c TL |
105 | values_cnt = rc; |
106 | ||
107 | r = calloc(1, sizeof(*r) + sizeof(struct spdk_json_val) * (values_cnt + 1)); | |
108 | if (!r) { | |
109 | return -errno; | |
110 | } | |
111 | ||
112 | if (client->resp) { | |
113 | free(r); | |
114 | return -ENOSPC; | |
115 | } | |
116 | ||
117 | client->resp = r; | |
118 | ||
119 | r->buf = client->recv_buf; | |
120 | buf_len = client->recv_offset; | |
121 | r->values_cnt = values_cnt; | |
122 | ||
123 | client->recv_buf_size = 0; | |
124 | client->recv_offset = 0; | |
125 | client->recv_buf = NULL; | |
126 | ||
11fdf7f2 | 127 | /* Decode a second time now that there is a full JSON value available. */ |
9f95a23c | 128 | rc = spdk_json_parse(r->buf, buf_len, r->values, values_cnt, &end, |
11fdf7f2 | 129 | SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE); |
9f95a23c TL |
130 | if (rc != (ssize_t)values_cnt) { |
131 | SPDK_ERRLOG("JSON parse error on second pass (rc: %zd, expected: %zu)\n", rc, values_cnt); | |
132 | goto err; | |
11fdf7f2 TL |
133 | } |
134 | ||
135 | assert(end != NULL); | |
136 | ||
9f95a23c | 137 | if (r->values[0].type != SPDK_JSON_VAL_OBJECT_BEGIN) { |
11fdf7f2 | 138 | SPDK_ERRLOG("top-level JSON value was not object\n"); |
9f95a23c TL |
139 | goto err; |
140 | } | |
141 | ||
142 | if (spdk_json_decode_object(r->values, jsonrpc_response_decoders, | |
143 | SPDK_COUNTOF(jsonrpc_response_decoders), &r->jsonrpc)) { | |
144 | goto err; | |
11fdf7f2 TL |
145 | } |
146 | ||
9f95a23c TL |
147 | r->ready = 1; |
148 | return 1; | |
11fdf7f2 | 149 | |
9f95a23c TL |
150 | err: |
151 | client->resp = NULL; | |
152 | spdk_jsonrpc_client_free_response(&r->jsonrpc); | |
153 | return -EINVAL; | |
11fdf7f2 TL |
154 | } |
155 | ||
156 | static int | |
157 | jsonrpc_client_write_cb(void *cb_ctx, const void *data, size_t size) | |
158 | { | |
159 | struct spdk_jsonrpc_client_request *request = cb_ctx; | |
160 | size_t new_size = request->send_buf_size; | |
161 | ||
162 | while (new_size - request->send_len < size) { | |
163 | if (new_size >= SPDK_JSONRPC_SEND_BUF_SIZE_MAX) { | |
164 | SPDK_ERRLOG("Send buf exceeded maximum size (%zu)\n", | |
165 | (size_t)SPDK_JSONRPC_SEND_BUF_SIZE_MAX); | |
166 | return -ENOSPC; | |
167 | } | |
168 | ||
169 | new_size *= 2; | |
170 | } | |
171 | ||
172 | if (new_size != request->send_buf_size) { | |
173 | uint8_t *new_buf; | |
174 | ||
175 | new_buf = realloc(request->send_buf, new_size); | |
176 | if (new_buf == NULL) { | |
177 | SPDK_ERRLOG("Resizing send_buf failed (current size %zu, new size %zu)\n", | |
178 | request->send_buf_size, new_size); | |
179 | return -ENOMEM; | |
180 | } | |
181 | ||
182 | request->send_buf = new_buf; | |
183 | request->send_buf_size = new_size; | |
184 | } | |
185 | ||
186 | memcpy(request->send_buf + request->send_len, data, size); | |
187 | request->send_len += size; | |
188 | ||
189 | return 0; | |
190 | } | |
191 | ||
192 | struct spdk_json_write_ctx * | |
193 | spdk_jsonrpc_begin_request(struct spdk_jsonrpc_client_request *request, int32_t id, | |
194 | const char *method) | |
195 | { | |
196 | struct spdk_json_write_ctx *w; | |
197 | ||
198 | w = spdk_json_write_begin(jsonrpc_client_write_cb, request, 0); | |
199 | if (w == NULL) { | |
200 | return NULL; | |
201 | } | |
202 | ||
203 | spdk_json_write_object_begin(w); | |
204 | spdk_json_write_named_string(w, "jsonrpc", "2.0"); | |
205 | ||
206 | if (id >= 0) { | |
207 | spdk_json_write_named_int32(w, "id", id); | |
208 | } | |
209 | ||
210 | if (method) { | |
211 | spdk_json_write_named_string(w, "method", method); | |
212 | } | |
213 | ||
214 | return w; | |
215 | } | |
216 | ||
217 | void | |
218 | spdk_jsonrpc_end_request(struct spdk_jsonrpc_client_request *request, struct spdk_json_write_ctx *w) | |
219 | { | |
220 | assert(w != NULL); | |
221 | ||
222 | spdk_json_write_object_end(w); | |
223 | spdk_json_write_end(w); | |
224 | jsonrpc_client_write_cb(request, "\n", 1); | |
225 | } | |
226 | ||
227 | SPDK_LOG_REGISTER_COMPONENT("rpc_client", SPDK_LOG_RPC_CLIENT) |