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