GCC Code Coverage Report


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, &params);
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, &params);
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, &params);
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, &params);
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