Directory: | src/ |
---|---|
File: | src/json_rpc.c |
Date: | 2023-08-28 07:33:56 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 194 | 305 | 63.6% |
Branches: | 58 | 154 | 37.7% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2023 Egor Tensin <Egor.Tensin@gmail.com> | ||
3 | * This file is part of the "cimple" project. | ||
4 | * For details, see https://github.com/egor-tensin/cimple. | ||
5 | * Distributed under the MIT License. | ||
6 | */ | ||
7 | |||
8 | #include "json_rpc.h" | ||
9 | #include "json.h" | ||
10 | #include "log.h" | ||
11 | |||
12 | #include <json-c/json_object.h> | ||
13 | |||
14 | #include <stdint.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <string.h> | ||
17 | |||
18 | struct jsonrpc_request { | ||
19 | struct json_object *impl; | ||
20 | }; | ||
21 | |||
22 | struct jsonrpc_response { | ||
23 | struct json_object *impl; | ||
24 | }; | ||
25 | |||
26 | static const char *const jsonrpc_key_version = "jsonrpc"; | ||
27 | static const char *const jsonrpc_key_id = "id"; | ||
28 | static const char *const jsonrpc_key_method = "method"; | ||
29 | static const char *const jsonrpc_key_params = "params"; | ||
30 | |||
31 | static const char *const jsonrpc_value_version = "2.0"; | ||
32 | |||
33 | 45954 | static int jsonrpc_check_version(struct json_object *obj) | |
34 | { | ||
35 | 45954 | const char *key = jsonrpc_key_version; | |
36 | 45954 | const char *version = NULL; | |
37 | |||
38 | 45954 | int ret = json_get_string(obj, key, &version); | |
39 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (ret < 0) |
40 | ✗ | return ret; | |
41 | |||
42 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45954 times.
|
45954 | if (strcmp(version, jsonrpc_value_version)) { |
43 | ✗ | log_err("JSON-RPC: invalid '%s' value: %s\n", key, version); | |
44 | ✗ | return -1; | |
45 | } | ||
46 | |||
47 | 45954 | return 0; | |
48 | } | ||
49 | |||
50 | 64314 | static int jsonrpc_set_version(struct json_object *obj) | |
51 | { | ||
52 | 64314 | return json_set_string_const_key(obj, jsonrpc_key_version, jsonrpc_value_version); | |
53 | } | ||
54 | |||
55 | 18360 | static int jsonrpc_check_id_type(struct json_object *id) | |
56 | { | ||
57 |
2/4✓ Branch 1 taken 18360 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18360 times.
|
18360 | if (!json_object_is_type(id, json_type_string) && !json_object_is_type(id, json_type_int)) { |
58 | ✗ | log_err("JSON-RPC: key '%s' must be either an integer or a string\n", | |
59 | jsonrpc_key_id); | ||
60 | ✗ | return -1; | |
61 | } | ||
62 | 18360 | return 0; | |
63 | } | ||
64 | |||
65 | 45954 | static int jsonrpc_check_id(struct json_object *obj, int required) | |
66 | { | ||
67 | 45954 | const char *key = jsonrpc_key_id; | |
68 | |||
69 |
2/2✓ Branch 1 taken 27594 times.
✓ Branch 2 taken 18360 times.
|
45954 | if (!json_has(obj, key)) { |
70 |
1/2✓ Branch 0 taken 27594 times.
✗ Branch 1 not taken.
|
27594 | if (!required) |
71 | 27594 | return 0; | |
72 | ✗ | log_err("JSON-RPC: key is missing: %s\n", key); | |
73 | ✗ | return -1; | |
74 | } | ||
75 | |||
76 | 18360 | struct json_object *id = NULL; | |
77 | |||
78 | 18360 | int ret = json_get(obj, key, &id); | |
79 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18360 times.
|
18360 | if (ret < 0) |
80 | ✗ | return ret; | |
81 | 18360 | return jsonrpc_check_id_type(id); | |
82 | } | ||
83 | |||
84 | 9180 | static int jsonrpc_set_id(struct json_object *obj, int id) | |
85 | { | ||
86 | 9180 | return json_set_int_const_key(obj, jsonrpc_key_id, id); | |
87 | } | ||
88 | |||
89 | 36774 | static int jsonrpc_check_method(struct json_object *obj) | |
90 | { | ||
91 | 36774 | const char *key = jsonrpc_key_method; | |
92 | 36774 | const char *method = NULL; | |
93 | 36774 | return json_get_string(obj, key, &method); | |
94 | } | ||
95 | |||
96 | 36774 | static int jsonrpc_set_method(struct json_object *obj, const char *method) | |
97 | { | ||
98 | 36774 | return json_set_string_const_key(obj, jsonrpc_key_method, method); | |
99 | } | ||
100 | |||
101 | 27540 | static int jsonrpc_check_params_type(struct json_object *params) | |
102 | { | ||
103 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 27540 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
27540 | if (!json_object_is_type(params, json_type_object) && |
104 | ✗ | !json_object_is_type(params, json_type_array)) { | |
105 | ✗ | log_err("JSON-RPC: key '%s' must be either an object or an array\n", | |
106 | jsonrpc_key_params); | ||
107 | ✗ | return -1; | |
108 | } | ||
109 | 27540 | return 0; | |
110 | } | ||
111 | |||
112 | 36774 | static int jsonrpc_check_params(struct json_object *obj) | |
113 | { | ||
114 | 36774 | const char *key = jsonrpc_key_params; | |
115 | |||
116 |
2/2✓ Branch 1 taken 9234 times.
✓ Branch 2 taken 27540 times.
|
36774 | if (!json_has(obj, key)) |
117 | 9234 | return 0; | |
118 | |||
119 | 27540 | struct json_object *params = NULL; | |
120 | |||
121 | 27540 | int ret = json_get(obj, key, ¶ms); | |
122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) |
123 | ✗ | return ret; | |
124 | 27540 | return jsonrpc_check_params_type(params); | |
125 | } | ||
126 | |||
127 | ✗ | static int jsonrpc_set_params(struct json_object *obj, struct json_object *params) | |
128 | { | ||
129 | ✗ | const char *key = jsonrpc_key_params; | |
130 | |||
131 | ✗ | int ret = jsonrpc_check_params_type(params); | |
132 | ✗ | if (ret < 0) | |
133 | ✗ | return ret; | |
134 | ✗ | return json_set_const_key(obj, key, params); | |
135 | } | ||
136 | |||
137 | static const char *const jsonrpc_key_result = "result"; | ||
138 | static const char *const jsonrpc_key_error = "error"; | ||
139 | |||
140 | static const char *const jsonrpc_key_code = "code"; | ||
141 | static const char *const jsonrpc_key_message = "message"; | ||
142 | |||
143 | ✗ | static int jsonrpc_check_error(struct json_object *obj) | |
144 | { | ||
145 | ✗ | const char *key = jsonrpc_key_error; | |
146 | ✗ | struct json_object *error = NULL; | |
147 | |||
148 | ✗ | int ret = json_get(obj, key, &error); | |
149 | ✗ | if (ret < 0) | |
150 | ✗ | return ret; | |
151 | |||
152 | ✗ | int64_t code = -1; | |
153 | |||
154 | ✗ | ret = json_get_int(error, jsonrpc_key_code, &code); | |
155 | ✗ | if (ret < 0) { | |
156 | ✗ | log_err("JSON-RPC: key is missing or not an integer: %s\n", jsonrpc_key_code); | |
157 | ✗ | return -1; | |
158 | } | ||
159 | |||
160 | ✗ | const char *message = NULL; | |
161 | |||
162 | ✗ | ret = json_get_string(error, jsonrpc_key_message, &message); | |
163 | ✗ | if (ret < 0) { | |
164 | ✗ | log_err("JSON-RPC: key is missing or not a string: %s\n", jsonrpc_key_message); | |
165 | ✗ | return -1; | |
166 | } | ||
167 | |||
168 | ✗ | return ret; | |
169 | } | ||
170 | |||
171 | 9180 | static int jsonrpc_check_result_or_error(struct json_object *obj) | |
172 | { | ||
173 | 9180 | const char *key_result = jsonrpc_key_result; | |
174 | 9180 | const char *key_error = jsonrpc_key_error; | |
175 | |||
176 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 9180 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
9180 | if (!json_has(obj, key_result) && !json_has(obj, key_error)) { |
177 | ✗ | log_err("JSON-RPC: either '%s' or '%s' must be present\n", key_result, key_error); | |
178 | ✗ | return -1; | |
179 | } | ||
180 | |||
181 |
1/2✓ Branch 1 taken 9180 times.
✗ Branch 2 not taken.
|
9180 | if (json_has(obj, key_result)) |
182 | 9180 | return 0; | |
183 | |||
184 | ✗ | return jsonrpc_check_error(obj); | |
185 | } | ||
186 | |||
187 | 36774 | static int jsonrpc_request_create_internal(struct jsonrpc_request **_request, int *id, | |
188 | const char *method, struct json_object *params) | ||
189 | { | ||
190 | 36774 | int ret = 0; | |
191 | |||
192 | 36774 | struct jsonrpc_request *request = malloc(sizeof(struct jsonrpc_request)); | |
193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (!request) { |
194 | ✗ | log_errno("malloc"); | |
195 | ✗ | ret = -1; | |
196 | ✗ | goto exit; | |
197 | } | ||
198 | |||
199 | 36774 | request->impl = json_object_new_object(); | |
200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (!request->impl) { |
201 | ✗ | json_errno("json_object_new_object"); | |
202 | ✗ | ret = -1; | |
203 | ✗ | goto free; | |
204 | } | ||
205 | |||
206 | 36774 | ret = jsonrpc_set_version(request->impl); | |
207 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (ret < 0) |
208 | ✗ | goto free_impl; | |
209 | |||
210 |
2/2✓ Branch 0 taken 9180 times.
✓ Branch 1 taken 27594 times.
|
36774 | if (id) { |
211 | 9180 | ret = jsonrpc_set_id(request->impl, *id); | |
212 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
213 | ✗ | goto free_impl; | |
214 | } | ||
215 | |||
216 | 36774 | ret = jsonrpc_set_method(request->impl, method); | |
217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (ret < 0) |
218 | ✗ | goto free_impl; | |
219 | |||
220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (params) { |
221 | ✗ | ret = jsonrpc_set_params(request->impl, params); | |
222 | ✗ | if (ret < 0) | |
223 | ✗ | goto free_impl; | |
224 | } | ||
225 | |||
226 | 36774 | *_request = request; | |
227 | 36774 | goto exit; | |
228 | |||
229 | ✗ | free_impl: | |
230 | ✗ | json_object_put(request->impl); | |
231 | ✗ | free: | |
232 | ✗ | free(request); | |
233 | 36774 | exit: | |
234 | 36774 | return ret; | |
235 | } | ||
236 | |||
237 | 9180 | int jsonrpc_request_create(struct jsonrpc_request **_request, int id, const char *method, | |
238 | struct json_object *params) | ||
239 | { | ||
240 | 9180 | return jsonrpc_request_create_internal(_request, &id, method, params); | |
241 | } | ||
242 | |||
243 | 73548 | void jsonrpc_request_destroy(struct jsonrpc_request *request) | |
244 | { | ||
245 | 73548 | json_object_put(request->impl); | |
246 | 73548 | free(request); | |
247 | 73548 | } | |
248 | |||
249 | 27594 | int jsonrpc_notification_create(struct jsonrpc_request **_request, const char *method, | |
250 | struct json_object *params) | ||
251 | { | ||
252 | 27594 | return jsonrpc_request_create_internal(_request, NULL, method, params); | |
253 | } | ||
254 | |||
255 | 36774 | int jsonrpc_request_is_notification(const struct jsonrpc_request *request) | |
256 | { | ||
257 | 36774 | return !json_has(request->impl, jsonrpc_key_id); | |
258 | } | ||
259 | |||
260 | 36774 | static int jsonrpc_request_from_json(struct jsonrpc_request **_request, struct json_object *impl) | |
261 | { | ||
262 | 36774 | int ret = 0; | |
263 | |||
264 | 36774 | ret = jsonrpc_check_version(impl); | |
265 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (ret < 0) |
266 | ✗ | return ret; | |
267 | 36774 | ret = jsonrpc_check_id(impl, 0); | |
268 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (ret < 0) |
269 | ✗ | return ret; | |
270 | 36774 | ret = jsonrpc_check_method(impl); | |
271 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (ret < 0) |
272 | ✗ | return ret; | |
273 | 36774 | ret = jsonrpc_check_params(impl); | |
274 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (ret < 0) |
275 | ✗ | return ret; | |
276 | |||
277 | 36774 | struct jsonrpc_request *request = malloc(sizeof(struct jsonrpc_request)); | |
278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (!request) { |
279 | ✗ | log_errno("malloc"); | |
280 | ✗ | return -1; | |
281 | } | ||
282 | 36774 | request->impl = impl; | |
283 | |||
284 | 36774 | *_request = request; | |
285 | 36774 | return ret; | |
286 | } | ||
287 | |||
288 | 36774 | int jsonrpc_request_send(const struct jsonrpc_request *request, int fd) | |
289 | { | ||
290 | 36774 | return json_send(request->impl, fd); | |
291 | } | ||
292 | |||
293 | 36774 | int jsonrpc_request_recv(struct jsonrpc_request **request, int fd) | |
294 | { | ||
295 | 36774 | struct json_object *impl = json_recv(fd); | |
296 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (!impl) { |
297 | ✗ | log_err("JSON-RPC: failed to receive request\n"); | |
298 | ✗ | return -1; | |
299 | } | ||
300 | |||
301 | 36774 | int ret = jsonrpc_request_from_json(request, impl); | |
302 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (ret < 0) |
303 | ✗ | goto free_impl; | |
304 | |||
305 | 36774 | return ret; | |
306 | |||
307 | ✗ | free_impl: | |
308 | ✗ | json_object_put(impl); | |
309 | |||
310 | ✗ | return ret; | |
311 | } | ||
312 | |||
313 | 36774 | const char *jsonrpc_request_get_method(const struct jsonrpc_request *request) | |
314 | { | ||
315 | 36774 | const char *method = NULL; | |
316 | 36774 | int ret = json_get_string(request->impl, jsonrpc_key_method, &method); | |
317 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36774 times.
|
36774 | if (ret < 0) { |
318 | /* Should never happen. */ | ||
319 | ✗ | return NULL; | |
320 | } | ||
321 | 36774 | return method; | |
322 | } | ||
323 | |||
324 | 73440 | static struct json_object *jsonrpc_request_create_params(struct jsonrpc_request *request) | |
325 | { | ||
326 | 73440 | const char *const key = jsonrpc_key_params; | |
327 | |||
328 |
2/2✓ Branch 1 taken 27540 times.
✓ Branch 2 taken 45900 times.
|
73440 | if (!json_has(request->impl, key)) { |
329 | 27540 | struct json_object *params = json_object_new_object(); | |
330 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (!params) { |
331 | ✗ | json_errno("json_object_new_object"); | |
332 | ✗ | return NULL; | |
333 | } | ||
334 | 27540 | int ret = json_set(request->impl, key, params); | |
335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) { |
336 | ✗ | json_object_put(params); | |
337 | ✗ | return NULL; | |
338 | } | ||
339 | 27540 | return params; | |
340 | } | ||
341 | |||
342 | 45900 | struct json_object *params = NULL; | |
343 | 45900 | int ret = json_get(request->impl, key, ¶ms); | |
344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45900 times.
|
45900 | if (ret < 0) |
345 | ✗ | return NULL; | |
346 | 45900 | return params; | |
347 | } | ||
348 | |||
349 | 45900 | int jsonrpc_request_get_param_string(const struct jsonrpc_request *request, const char *name, | |
350 | const char **value) | ||
351 | { | ||
352 | 45900 | struct json_object *params = NULL; | |
353 | 45900 | int ret = json_get(request->impl, jsonrpc_key_params, ¶ms); | |
354 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45900 times.
|
45900 | if (ret < 0) |
355 | ✗ | return ret; | |
356 | 45900 | return json_get_string(params, name, value); | |
357 | } | ||
358 | |||
359 | 45900 | int jsonrpc_request_set_param_string(struct jsonrpc_request *request, const char *name, | |
360 | const char *value) | ||
361 | { | ||
362 | 45900 | struct json_object *params = jsonrpc_request_create_params(request); | |
363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45900 times.
|
45900 | if (!params) |
364 | ✗ | return -1; | |
365 | 45900 | return json_set_string(params, name, value); | |
366 | } | ||
367 | |||
368 | 27540 | int jsonrpc_request_get_param_int(const struct jsonrpc_request *request, const char *name, | |
369 | int64_t *value) | ||
370 | { | ||
371 | 27540 | struct json_object *params = NULL; | |
372 | 27540 | int ret = json_get(request->impl, jsonrpc_key_params, ¶ms); | |
373 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) |
374 | ✗ | return ret; | |
375 | 27540 | return json_get_int(params, name, value); | |
376 | } | ||
377 | |||
378 | 27540 | int jsonrpc_request_set_param_int(struct jsonrpc_request *request, const char *name, int64_t value) | |
379 | { | ||
380 | 27540 | struct json_object *params = jsonrpc_request_create_params(request); | |
381 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (!params) |
382 | ✗ | return -1; | |
383 | 27540 | return json_set_int(params, name, value); | |
384 | } | ||
385 | |||
386 | 27540 | int jsonrpc_response_create_internal(struct jsonrpc_response **_response, | |
387 | const struct jsonrpc_request *request, | ||
388 | struct json_object *result, struct json_object *error) | ||
389 | { | ||
390 | 27540 | int ret = 0; | |
391 | |||
392 | 27540 | struct jsonrpc_response *response = malloc(sizeof(struct jsonrpc_response)); | |
393 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (!response) { |
394 | ✗ | log_errno("malloc"); | |
395 | ✗ | ret = -1; | |
396 | ✗ | goto exit; | |
397 | } | ||
398 | |||
399 | 27540 | response->impl = json_object_new_object(); | |
400 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (!response->impl) { |
401 | ✗ | json_errno("json_object_new_object"); | |
402 | ✗ | ret = -1; | |
403 | ✗ | goto free; | |
404 | } | ||
405 | |||
406 | 27540 | ret = jsonrpc_set_version(response->impl); | |
407 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) |
408 | ✗ | goto free_impl; | |
409 | |||
410 | 27540 | struct json_object *id = NULL; | |
411 | 27540 | ret = json_clone(request->impl, jsonrpc_key_id, &id); | |
412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) |
413 | ✗ | goto free_impl; | |
414 | |||
415 | 27540 | ret = json_set(response->impl, jsonrpc_key_id, id); | |
416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27540 times.
|
27540 | if (ret < 0) { |
417 | ✗ | json_object_put(id); | |
418 | ✗ | goto free_impl; | |
419 | } | ||
420 | |||
421 |
2/2✓ Branch 0 taken 9180 times.
✓ Branch 1 taken 18360 times.
|
27540 | if (error) { |
422 | 9180 | ret = json_set_const_key(response->impl, jsonrpc_key_error, error); | |
423 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
424 | ✗ | goto free_impl; | |
425 | } else { | ||
426 | 18360 | ret = json_set_const_key(response->impl, jsonrpc_key_result, result); | |
427 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18360 times.
|
18360 | if (ret < 0) |
428 | ✗ | goto free_impl; | |
429 | } | ||
430 | |||
431 | 27540 | *_response = response; | |
432 | 27540 | goto exit; | |
433 | |||
434 | ✗ | free_impl: | |
435 | ✗ | json_object_put(response->impl); | |
436 | ✗ | free: | |
437 | ✗ | free(response); | |
438 | 27540 | exit: | |
439 | 27540 | return ret; | |
440 | } | ||
441 | |||
442 | 18360 | int jsonrpc_response_create(struct jsonrpc_response **response, | |
443 | const struct jsonrpc_request *request, struct json_object *result) | ||
444 | { | ||
445 | 18360 | return jsonrpc_response_create_internal(response, request, result, NULL); | |
446 | } | ||
447 | |||
448 | 36720 | void jsonrpc_response_destroy(struct jsonrpc_response *response) | |
449 | { | ||
450 | 36720 | json_object_put(response->impl); | |
451 | 36720 | free(response); | |
452 | 36720 | } | |
453 | |||
454 | 9180 | int jsonrpc_error_create(struct jsonrpc_response **response, struct jsonrpc_request *request, | |
455 | int code, const char *message) | ||
456 | { | ||
457 | 9180 | struct json_object *error = json_object_new_object(); | |
458 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (!error) { |
459 | ✗ | json_errno("json_object_new_object"); | |
460 | ✗ | return -1; | |
461 | } | ||
462 | |||
463 | 9180 | int ret = 0; | |
464 | |||
465 | 9180 | ret = json_set_int_const_key(error, jsonrpc_key_code, code); | |
466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
467 | ✗ | goto free; | |
468 | 9180 | ret = json_set_string_const_key(error, jsonrpc_key_message, message); | |
469 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
470 | ✗ | goto free; | |
471 | |||
472 | 9180 | ret = jsonrpc_response_create_internal(response, request, NULL, error); | |
473 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
474 | ✗ | goto free; | |
475 | |||
476 | 9180 | return ret; | |
477 | |||
478 | ✗ | free: | |
479 | ✗ | json_object_put(error); | |
480 | |||
481 | ✗ | return ret; | |
482 | } | ||
483 | |||
484 | 9180 | int jsonrpc_response_is_error(const struct jsonrpc_response *response) | |
485 | { | ||
486 | 9180 | return json_has(response->impl, jsonrpc_key_error); | |
487 | } | ||
488 | |||
489 | 9180 | static int jsonrpc_response_from_json(struct jsonrpc_response **_response, struct json_object *impl) | |
490 | { | ||
491 | 9180 | int ret = 0; | |
492 | |||
493 | 9180 | ret = jsonrpc_check_version(impl); | |
494 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
495 | ✗ | return ret; | |
496 | 9180 | ret = jsonrpc_check_id(impl, 1); | |
497 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
498 | ✗ | return ret; | |
499 | 9180 | ret = jsonrpc_check_result_or_error(impl); | |
500 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
501 | ✗ | return ret; | |
502 | |||
503 | 9180 | struct jsonrpc_response *response = malloc(sizeof(struct jsonrpc_response)); | |
504 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (!response) { |
505 | ✗ | log_errno("malloc"); | |
506 | ✗ | return -1; | |
507 | } | ||
508 | 9180 | response->impl = impl; | |
509 | |||
510 | 9180 | *_response = response; | |
511 | 9180 | return ret; | |
512 | } | ||
513 | |||
514 | 9180 | int jsonrpc_response_send(const struct jsonrpc_response *response, int fd) | |
515 | { | ||
516 | 9180 | return json_send(response->impl, fd); | |
517 | } | ||
518 | |||
519 | 9180 | int jsonrpc_response_recv(struct jsonrpc_response **response, int fd) | |
520 | { | ||
521 | 9180 | struct json_object *impl = json_recv(fd); | |
522 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (!impl) { |
523 | ✗ | log_err("JSON-RPC: failed to receive response\n"); | |
524 | ✗ | return -1; | |
525 | } | ||
526 | |||
527 | 9180 | int ret = jsonrpc_response_from_json(response, impl); | |
528 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
529 | ✗ | goto free_impl; | |
530 | |||
531 | 9180 | return ret; | |
532 | |||
533 | ✗ | free_impl: | |
534 | ✗ | json_object_put(impl); | |
535 | |||
536 | ✗ | return ret; | |
537 | } | ||
538 |