Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2006 Voice Sistem SRL |
3 | | * Copyright (C) 2018 OpenSIPS Solutions |
4 | | * |
5 | | * This file is part of opensips, a free SIP server. |
6 | | * |
7 | | * opensips is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 2 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * opensips is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | | * |
21 | | * |
22 | | */ |
23 | | |
24 | | #include <string.h> |
25 | | #include <stdio.h> |
26 | | #include <errno.h> |
27 | | #include <stdlib.h> |
28 | | #include "../mem/mem.h" |
29 | | #include "../mem/shm_mem.h" |
30 | | #include "../dprint.h" |
31 | | #include "../ut.h" |
32 | | #include "item.h" |
33 | | #include "fmt.h" |
34 | | |
35 | 0 | #define MI_PARAM_ERR_BUFLEN 255 |
36 | | |
37 | 0 | #define MI_PARAM_ERR_MISSING -1 |
38 | 0 | #define MI_PARAM_ERR_BAD_TYPE -2 |
39 | 0 | #define MI_PARAM_ERR_EMPTY_ARR -3 |
40 | 0 | #define MI_PARAM_ERR_ARR_BAD_TYPE -4 |
41 | | |
42 | | int param_err_type = -2; |
43 | | char *param_err_pname; |
44 | | |
45 | | static mi_response_t *_init_mi_result(mi_item_t **item_out, int type, int dval, |
46 | | const char *sval, int sval_len) |
47 | 0 | { |
48 | 0 | mi_response_t *res = NULL; |
49 | 0 | mi_item_t *jsonrpc_vers; |
50 | |
|
51 | 0 | _init_mi_sys_mem_hooks(); |
52 | |
|
53 | 0 | res = cJSON_CreateObject(); |
54 | 0 | if (!res) |
55 | 0 | goto error; |
56 | | |
57 | 0 | jsonrpc_vers = cJSON_CreateString(JSONRPC_VERS_S); |
58 | 0 | if (!jsonrpc_vers) |
59 | 0 | goto error; |
60 | 0 | cJSON_AddItemToObject(res, JSONRPC_S, jsonrpc_vers); |
61 | |
|
62 | 0 | switch (type) { |
63 | 0 | case cJSON_Array: |
64 | 0 | *item_out = cJSON_CreateArray(); |
65 | 0 | break; |
66 | 0 | case cJSON_Object: |
67 | 0 | *item_out = cJSON_CreateObject(); |
68 | 0 | break; |
69 | 0 | case cJSON_String: |
70 | 0 | *item_out = cJSON_CreateStr(sval, sval_len); |
71 | 0 | break; |
72 | 0 | case cJSON_Number: |
73 | 0 | *item_out = cJSON_CreateNumber(dval); |
74 | 0 | break; |
75 | 0 | case cJSON_True: |
76 | 0 | *item_out = cJSON_CreateTrue(); |
77 | 0 | break; |
78 | 0 | case cJSON_False: |
79 | 0 | *item_out = cJSON_CreateFalse(); |
80 | 0 | break; |
81 | 0 | case cJSON_NULL: |
82 | 0 | *item_out = cJSON_CreateNull(); |
83 | 0 | break; |
84 | 0 | default: |
85 | 0 | *item_out = NULL; |
86 | 0 | LM_BUG("Unknown MI item type: %d\n", type); |
87 | 0 | goto error; |
88 | 0 | } |
89 | 0 | if (!*item_out) |
90 | 0 | goto error; |
91 | | |
92 | 0 | cJSON_AddItemToObject(res, JSONRPC_RESULT_S, *item_out); |
93 | |
|
94 | 0 | _init_mi_pkg_mem_hooks(); |
95 | 0 | return res; |
96 | | |
97 | 0 | error: |
98 | 0 | if (res) |
99 | 0 | cJSON_Delete(res); |
100 | 0 | _init_mi_pkg_mem_hooks(); |
101 | 0 | return NULL; |
102 | 0 | } |
103 | | |
104 | | |
105 | | mi_response_t *init_mi_result_array(mi_item_t **arr_out) |
106 | 0 | { |
107 | 0 | return _init_mi_result(arr_out, cJSON_Array, 0, NULL, 0); |
108 | 0 | } |
109 | | |
110 | | mi_response_t *init_mi_result_object(mi_item_t **obj_out) |
111 | 0 | { |
112 | 0 | return _init_mi_result(obj_out, cJSON_Object, 0, NULL, 0); |
113 | 0 | } |
114 | | |
115 | | mi_response_t *init_mi_result_string(const char *value, int value_len) |
116 | 0 | { |
117 | 0 | mi_item_t *item; |
118 | |
|
119 | 0 | return _init_mi_result(&item, cJSON_String, 0, value, value_len); |
120 | 0 | } |
121 | | |
122 | | mi_response_t *init_mi_result_number(double value) |
123 | 0 | { |
124 | 0 | mi_item_t *item; |
125 | |
|
126 | 0 | return _init_mi_result(&item, cJSON_Number, value, NULL, 0); |
127 | 0 | } |
128 | | |
129 | | mi_response_t *init_mi_result_bool(int b) |
130 | 0 | { |
131 | 0 | mi_item_t *item; |
132 | |
|
133 | 0 | return _init_mi_result(&item, b ? cJSON_True : cJSON_False, 0, NULL, 0); |
134 | 0 | } |
135 | | |
136 | | mi_response_t *init_mi_result_null(void) |
137 | 0 | { |
138 | 0 | mi_item_t *item; |
139 | |
|
140 | 0 | return _init_mi_result(&item, cJSON_NULL, 0, NULL, 0); |
141 | 0 | } |
142 | | |
143 | | mi_response_t *init_mi_error_extra(int code, const char *msg, int msg_len, |
144 | | const char *details, int details_len) |
145 | 0 | { |
146 | 0 | mi_response_t *res; |
147 | 0 | mi_item_t *err_item = NULL, *msg_item = NULL, *code_item = NULL, *data_item; |
148 | 0 | mi_item_t *jsonrpc_vers; |
149 | |
|
150 | 0 | _init_mi_sys_mem_hooks(); |
151 | |
|
152 | 0 | res = cJSON_CreateObject(); |
153 | 0 | if (!res) |
154 | 0 | goto error; |
155 | | |
156 | 0 | jsonrpc_vers = cJSON_CreateString(JSONRPC_VERS_S); |
157 | 0 | if (!jsonrpc_vers) |
158 | 0 | goto error; |
159 | 0 | cJSON_AddItemToObject(res, JSONRPC_S, jsonrpc_vers); |
160 | |
|
161 | 0 | err_item = cJSON_CreateObject(); |
162 | 0 | if (!err_item) |
163 | 0 | goto error; |
164 | 0 | cJSON_AddItemToObject(res, JSONRPC_ERROR_S, err_item); |
165 | |
|
166 | 0 | code_item = cJSON_CreateNumber(code); |
167 | 0 | if (!code_item) |
168 | 0 | goto error; |
169 | 0 | cJSON_AddItemToObject(err_item, JSONRPC_ERR_CODE_S, code_item); |
170 | |
|
171 | 0 | msg_item = cJSON_CreateStr(msg, msg_len); |
172 | 0 | if (!msg_item) |
173 | 0 | goto error; |
174 | 0 | cJSON_AddItemToObject(err_item, JSONRPC_ERR_MSG_S, msg_item); |
175 | |
|
176 | 0 | if (details && details_len) { |
177 | 0 | data_item = cJSON_CreateStr(details, details_len); |
178 | 0 | if (!data_item) |
179 | 0 | goto error; |
180 | 0 | cJSON_AddItemToObject(err_item, JSONRPC_ERR_DATA_S, data_item); |
181 | 0 | } |
182 | | |
183 | 0 | _init_mi_pkg_mem_hooks(); |
184 | 0 | return res; |
185 | | |
186 | 0 | error: |
187 | 0 | if (res) |
188 | 0 | cJSON_Delete(res); |
189 | |
|
190 | 0 | _init_mi_pkg_mem_hooks(); |
191 | 0 | return NULL; |
192 | 0 | } |
193 | | |
194 | | void free_mi_response(mi_response_t *response) |
195 | 0 | { |
196 | 0 | _init_mi_sys_mem_hooks(); |
197 | |
|
198 | 0 | cJSON_Delete(response); |
199 | |
|
200 | 0 | _init_mi_pkg_mem_hooks(); |
201 | 0 | } |
202 | | |
203 | | static mi_item_t *_add_mi_item(mi_item_t *to, char *name, int name_len, |
204 | | int type, double dval, const char *sval, int sval_len) |
205 | 0 | { |
206 | 0 | mi_item_t *item = NULL; |
207 | 0 | str name_str; |
208 | |
|
209 | 0 | _init_mi_sys_mem_hooks(); |
210 | |
|
211 | 0 | switch (type) { |
212 | 0 | case cJSON_Array: |
213 | 0 | item = cJSON_CreateArray(); |
214 | 0 | break; |
215 | 0 | case cJSON_Object: |
216 | 0 | item = cJSON_CreateObject(); |
217 | 0 | break; |
218 | 0 | case cJSON_String: |
219 | 0 | if (!sval || sval_len == 0) |
220 | 0 | item = cJSON_CreateStr("", 0); |
221 | 0 | else |
222 | 0 | item = cJSON_CreateStr(sval, sval_len); |
223 | 0 | break; |
224 | 0 | case cJSON_Number: |
225 | 0 | item = cJSON_CreateNumber(dval); |
226 | 0 | break; |
227 | 0 | case cJSON_True: |
228 | 0 | item = cJSON_CreateTrue(); |
229 | 0 | break; |
230 | 0 | case cJSON_False: |
231 | 0 | item = cJSON_CreateFalse(); |
232 | 0 | break; |
233 | 0 | case cJSON_NULL: |
234 | 0 | item = cJSON_CreateNull(); |
235 | 0 | break; |
236 | 0 | default: |
237 | 0 | item = NULL; |
238 | 0 | LM_BUG("Unknown MI item type: %d\n", type); |
239 | 0 | goto out; |
240 | 0 | } |
241 | | |
242 | 0 | if (!item) |
243 | 0 | goto out; |
244 | | |
245 | 0 | if (MI_ITEM_IS_ARRAY(to)) |
246 | 0 | cJSON_AddItemToArray(to, item); |
247 | 0 | else { |
248 | 0 | name_str.len = name_len; |
249 | 0 | name_str.s = name; |
250 | 0 | _cJSON_AddItemToObject(to, &name_str, item); |
251 | 0 | } |
252 | |
|
253 | 0 | out: |
254 | 0 | _init_mi_pkg_mem_hooks(); |
255 | 0 | return item; |
256 | 0 | } |
257 | | |
258 | | mi_item_t *add_mi_array(mi_item_t *to, char *name, int name_len) |
259 | 0 | { |
260 | 0 | return _add_mi_item(to, name, name_len, cJSON_Array, 0, NULL, 0); |
261 | 0 | } |
262 | | |
263 | | mi_item_t *add_mi_object(mi_item_t *to, char *name, int name_len) |
264 | 0 | { |
265 | 0 | return _add_mi_item(to, name, name_len, cJSON_Object, 0, NULL, 0); |
266 | 0 | } |
267 | | |
268 | | int add_mi_string(mi_item_t *to, char *name, int name_len, |
269 | | const char *value, int value_len) |
270 | 0 | { |
271 | 0 | return _add_mi_item(to, name, name_len, cJSON_String, 0, value, value_len) ? |
272 | 0 | 0 : -1; |
273 | 0 | } |
274 | | |
275 | | int add_mi_string_fmt(mi_item_t *to, char *name, int name_len, |
276 | | char *fmt_val, ...) |
277 | 0 | { |
278 | 0 | va_list ap; |
279 | 0 | char *value; |
280 | 0 | int value_len; |
281 | |
|
282 | 0 | va_start(ap, fmt_val); |
283 | 0 | value = mi_print_fmt(fmt_val, ap, &value_len); |
284 | 0 | va_end(ap); |
285 | 0 | if (!value) |
286 | 0 | return -1; |
287 | | |
288 | 0 | return _add_mi_item(to, name, name_len, cJSON_String, 0, value, value_len) ? |
289 | 0 | 0 : -1; |
290 | 0 | } |
291 | | |
292 | | int add_mi_number(mi_item_t *to, char *name, int name_len, double value) |
293 | 0 | { |
294 | 0 | return _add_mi_item(to, name, name_len, cJSON_Number, value, NULL, 0) ? |
295 | 0 | 0 : -1; |
296 | 0 | } |
297 | | |
298 | | int add_mi_bool(mi_item_t *to, char *name, int name_len, int b) |
299 | 0 | { |
300 | 0 | return _add_mi_item(to, name, name_len, b ? cJSON_True : cJSON_False, |
301 | 0 | 0, NULL, 0) ? 0 : -1; |
302 | 0 | } |
303 | | |
304 | | int add_mi_null(mi_item_t *to, char *name, int name_len) |
305 | 0 | { |
306 | 0 | return _add_mi_item(to, name, name_len, cJSON_NULL, 0, NULL, 0) ? |
307 | 0 | 0 : -1; |
308 | 0 | } |
309 | | |
310 | | mi_response_t *shm_clone_mi_response(mi_response_t *src) |
311 | 0 | { |
312 | 0 | mi_response_t *copy; |
313 | |
|
314 | 0 | _init_mi_shm_mem_hooks(); |
315 | |
|
316 | 0 | copy = cJSON_Duplicate(src, 1); |
317 | |
|
318 | 0 | _init_mi_pkg_mem_hooks(); |
319 | |
|
320 | 0 | return copy; |
321 | 0 | } |
322 | | |
323 | | void free_shm_mi_response(mi_response_t *shm_response) |
324 | 0 | { |
325 | | /* if there is an id, this is probably in pkg mem, because that's how |
326 | | * add_id_to_response adds it; if we don't release it now, removing it |
327 | | * from shm will result in a memory corruption */ |
328 | 0 | _init_mi_sys_mem_hooks(); |
329 | 0 | cJSON_DeleteItemFromObject(shm_response, "id"); |
330 | |
|
331 | 0 | _init_mi_shm_mem_hooks(); |
332 | |
|
333 | 0 | cJSON_Delete(shm_response); |
334 | |
|
335 | 0 | _init_mi_pkg_mem_hooks(); |
336 | 0 | } |
337 | | |
338 | | mi_item_t *shm_clone_mi_item(mi_item_t *src) |
339 | 0 | { |
340 | 0 | mi_item_t *copy; |
341 | |
|
342 | 0 | _init_mi_shm_mem_hooks(); |
343 | |
|
344 | 0 | copy = cJSON_Duplicate(src, 1); |
345 | |
|
346 | 0 | _init_mi_pkg_mem_hooks(); |
347 | |
|
348 | 0 | return copy; |
349 | 0 | } |
350 | | |
351 | | void free_shm_mi_item(mi_item_t *item) |
352 | 0 | { |
353 | 0 | _init_mi_shm_mem_hooks(); |
354 | |
|
355 | 0 | cJSON_Delete(item); |
356 | |
|
357 | 0 | _init_mi_pkg_mem_hooks(); |
358 | 0 | } |
359 | | |
360 | | static mi_item_t * _get_mi_param(const mi_params_t *params, char *name) |
361 | 0 | { |
362 | 0 | int i; |
363 | |
|
364 | 0 | if (!params->item) |
365 | 0 | return NULL; |
366 | | |
367 | 0 | if (MI_ITEM_IS_ARRAY(params->item)) { |
368 | 0 | for (i = 0; params->list[i]; i++) |
369 | 0 | if (!strcmp(params->list[i], name)) |
370 | 0 | break; |
371 | |
|
372 | 0 | if (!params->list[i]) |
373 | 0 | return NULL; |
374 | | |
375 | 0 | return cJSON_GetArrayItem(params->item, i); |
376 | 0 | } else |
377 | 0 | return cJSON_GetObjectItem(params->item, name); |
378 | 0 | } |
379 | | |
380 | | int try_get_mi_int_param(const mi_params_t *params, char *name, int *value) |
381 | 0 | { |
382 | 0 | mi_item_t *p; |
383 | 0 | str st; |
384 | |
|
385 | 0 | param_err_pname = name; |
386 | |
|
387 | 0 | p = _get_mi_param(params, name); |
388 | 0 | if (!p) { |
389 | 0 | param_err_type = MI_PARAM_ERR_MISSING; |
390 | 0 | return MI_PARAM_ERR_MISSING; |
391 | 0 | } |
392 | | |
393 | 0 | if (!(p->type & (cJSON_Number|cJSON_String))) { |
394 | 0 | param_err_type = MI_PARAM_ERR_BAD_TYPE; |
395 | 0 | return MI_PARAM_ERR_BAD_TYPE; |
396 | 0 | } |
397 | | |
398 | 0 | if (p->type & cJSON_Number) { |
399 | 0 | *value = p->valueint; |
400 | 0 | } else { |
401 | 0 | st.s = p->valuestring; |
402 | 0 | st.len = strlen(st.s); |
403 | 0 | if (str2sint(&st, value) < 0) { |
404 | 0 | param_err_type = MI_PARAM_ERR_BAD_TYPE; |
405 | 0 | return MI_PARAM_ERR_BAD_TYPE; |
406 | 0 | } |
407 | 0 | } |
408 | | |
409 | 0 | return 0; |
410 | 0 | } |
411 | | |
412 | | int get_mi_int_param(const mi_params_t *params, char *name, int *value) |
413 | 0 | { |
414 | 0 | switch (try_get_mi_int_param(params, name, value)) |
415 | 0 | { |
416 | 0 | case MI_PARAM_ERR_MISSING: |
417 | 0 | LM_ERR("Parameter: %s not found\n", name); |
418 | 0 | break; |
419 | 0 | case MI_PARAM_ERR_BAD_TYPE: |
420 | 0 | LM_ERR("Parameter: %s is not an valid integer\n", name); |
421 | 0 | break; |
422 | 0 | case 0: |
423 | 0 | return 0; |
424 | 0 | } |
425 | 0 | return -1; |
426 | 0 | } |
427 | | |
428 | | int try_get_mi_string_param(const mi_params_t *params, char *name, |
429 | | char **value, int *value_len) |
430 | 0 | { |
431 | 0 | mi_item_t *p; |
432 | |
|
433 | 0 | param_err_pname = name; |
434 | |
|
435 | 0 | p = _get_mi_param(params, name); |
436 | 0 | if (!p) { |
437 | 0 | param_err_type = MI_PARAM_ERR_MISSING; |
438 | 0 | return MI_PARAM_ERR_MISSING; |
439 | 0 | } |
440 | | |
441 | 0 | if (!(p->type & (cJSON_Number|cJSON_String))) { |
442 | 0 | param_err_type = MI_PARAM_ERR_BAD_TYPE; |
443 | 0 | return MI_PARAM_ERR_BAD_TYPE; |
444 | 0 | } |
445 | | |
446 | 0 | if (p->type & cJSON_String) { |
447 | 0 | *value = p->valuestring; |
448 | 0 | *value_len = strlen(p->valuestring); |
449 | 0 | } else { |
450 | 0 | *value = sint2str(p->valueint, value_len); |
451 | 0 | } |
452 | |
|
453 | 0 | return 0; |
454 | 0 | } |
455 | | |
456 | | int get_mi_string_param(const mi_params_t *params, char *name, |
457 | | char **value, int *value_len) |
458 | 0 | { |
459 | 0 | switch (try_get_mi_string_param(params, name, value, value_len)) |
460 | 0 | { |
461 | 0 | case MI_PARAM_ERR_MISSING: |
462 | 0 | LM_ERR("Parameter: %s not found\n", name); |
463 | 0 | break; |
464 | 0 | case MI_PARAM_ERR_BAD_TYPE: |
465 | 0 | LM_ERR("Bad data type for parameter: %s\n", name); |
466 | 0 | break; |
467 | 0 | case 0: |
468 | 0 | return 0; |
469 | 0 | } |
470 | 0 | return -1; |
471 | 0 | } |
472 | | |
473 | | |
474 | | int get_mi_bool_like_param(const mi_params_t *params, char *name, |
475 | | int default_value) |
476 | 0 | { |
477 | 0 | str tmp; |
478 | |
|
479 | 0 | if (try_get_mi_string_param(params, name, &tmp.s, &tmp.len) != 0) |
480 | 0 | return default_value; |
481 | | |
482 | 0 | if (tmp.len != 1) |
483 | 0 | return default_value; |
484 | | |
485 | 0 | if (tmp.s[0] == '0' || tmp.s[0] == 'n' || tmp.s[0] == 'N') |
486 | 0 | return 0; |
487 | | |
488 | 0 | if (tmp.s[0] == '1' || tmp.s[0] == 'y' || tmp.s[0] == 'Y') |
489 | 0 | return 1; |
490 | | |
491 | 0 | return default_value; |
492 | 0 | } |
493 | | |
494 | | int try_get_mi_array_param(const mi_params_t *params, char *name, |
495 | | mi_item_t **value, int *no_items) |
496 | 0 | { |
497 | 0 | mi_item_t *p; |
498 | |
|
499 | 0 | param_err_pname = name; |
500 | |
|
501 | 0 | p = _get_mi_param(params, name);; |
502 | 0 | if (!p) { |
503 | 0 | param_err_type = MI_PARAM_ERR_MISSING; |
504 | 0 | return MI_PARAM_ERR_MISSING; |
505 | 0 | } |
506 | | |
507 | 0 | if (!(p->type & cJSON_Array)) { |
508 | 0 | param_err_type = MI_PARAM_ERR_BAD_TYPE; |
509 | 0 | return MI_PARAM_ERR_BAD_TYPE; |
510 | 0 | } |
511 | | |
512 | 0 | *value = p; |
513 | 0 | *no_items = cJSON_GetArraySize(p); |
514 | 0 | if (*no_items == 0) { |
515 | 0 | param_err_type = MI_PARAM_ERR_EMPTY_ARR; |
516 | 0 | return MI_PARAM_ERR_EMPTY_ARR; |
517 | 0 | } |
518 | | |
519 | 0 | return 0; |
520 | 0 | } |
521 | | |
522 | | int get_mi_array_param(const mi_params_t *params, char *name, |
523 | | mi_item_t **value, int *no_items) |
524 | 0 | { |
525 | 0 | switch (try_get_mi_array_param(params, name, value, no_items)) |
526 | 0 | { |
527 | 0 | case MI_PARAM_ERR_MISSING: |
528 | 0 | LM_ERR("Parameter: %s not found\n", name); |
529 | 0 | break; |
530 | 0 | case MI_PARAM_ERR_BAD_TYPE: |
531 | 0 | LM_ERR("Parameter: %s is not an array\n", name); |
532 | 0 | break; |
533 | 0 | case MI_PARAM_ERR_EMPTY_ARR: |
534 | 0 | LM_ERR("Empty array for parameter: %s\n", name); |
535 | 0 | break; |
536 | 0 | case 0: |
537 | 0 | return 0; |
538 | 0 | } |
539 | 0 | return -1; |
540 | 0 | } |
541 | | |
542 | | int try_get_mi_arr_param_string(const mi_item_t *array, int pos, |
543 | | char **value, int *value_len) |
544 | 0 | { |
545 | 0 | mi_item_t *s; |
546 | |
|
547 | 0 | if (!array) { |
548 | 0 | param_err_type = MI_PARAM_ERR_MISSING; |
549 | 0 | return MI_PARAM_ERR_MISSING; |
550 | 0 | } |
551 | | |
552 | 0 | s = cJSON_GetArrayItem(array, pos); |
553 | 0 | if (!s) { |
554 | 0 | param_err_type = MI_PARAM_ERR_MISSING; |
555 | 0 | return MI_PARAM_ERR_MISSING; |
556 | 0 | } |
557 | | |
558 | 0 | if (!(s->type & (cJSON_Number|cJSON_String))) { |
559 | 0 | param_err_type = MI_PARAM_ERR_ARR_BAD_TYPE; |
560 | 0 | return MI_PARAM_ERR_ARR_BAD_TYPE; |
561 | 0 | } |
562 | | |
563 | 0 | if (s->type & cJSON_String) { |
564 | 0 | *value = s->valuestring; |
565 | 0 | *value_len = strlen(s->valuestring); |
566 | 0 | } else { |
567 | 0 | *value = sint2str(s->valueint, value_len); |
568 | 0 | } |
569 | |
|
570 | 0 | return 0; |
571 | 0 | } |
572 | | |
573 | | int get_mi_arr_param_string(const mi_item_t *array, int pos, |
574 | | char **value, int *value_len) |
575 | 0 | { |
576 | 0 | switch (try_get_mi_arr_param_string(array, pos, value, value_len)) |
577 | 0 | { |
578 | 0 | case MI_PARAM_ERR_MISSING: |
579 | 0 | LM_ERR("Array index out of bounds\n"); |
580 | 0 | break; |
581 | 0 | case MI_PARAM_ERR_ARR_BAD_TYPE: |
582 | 0 | LM_ERR("Bad data type for array item\n"); |
583 | 0 | break; |
584 | 0 | case 0: |
585 | 0 | return 0; |
586 | 0 | } |
587 | 0 | return -1; |
588 | 0 | } |
589 | | |
590 | | int try_get_mi_arr_param_int(const mi_item_t *array, int pos, int *value) |
591 | 0 | { |
592 | 0 | mi_item_t *i; |
593 | 0 | str st; |
594 | |
|
595 | 0 | if (!array) { |
596 | 0 | param_err_type = MI_PARAM_ERR_MISSING; |
597 | 0 | return MI_PARAM_ERR_MISSING; |
598 | 0 | } |
599 | | |
600 | 0 | i = cJSON_GetArrayItem(array, pos); |
601 | 0 | if (!i) { |
602 | 0 | param_err_type = MI_PARAM_ERR_MISSING; |
603 | 0 | return MI_PARAM_ERR_MISSING; |
604 | 0 | } |
605 | | |
606 | 0 | if (!(i->type & (cJSON_Number|cJSON_String))) { |
607 | 0 | param_err_type = MI_PARAM_ERR_ARR_BAD_TYPE; |
608 | 0 | return MI_PARAM_ERR_ARR_BAD_TYPE; |
609 | 0 | } |
610 | | |
611 | 0 | if (i->type & cJSON_Number) { |
612 | 0 | *value = i->valueint; |
613 | 0 | } else { |
614 | 0 | st.s = i->valuestring; |
615 | 0 | st.len = strlen(st.s); |
616 | 0 | if (str2sint(&st, value) < 0) { |
617 | 0 | param_err_type = MI_PARAM_ERR_ARR_BAD_TYPE; |
618 | 0 | return MI_PARAM_ERR_ARR_BAD_TYPE; |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | 0 | return 0; |
623 | 0 | } |
624 | | |
625 | | int get_mi_arr_param_int(const mi_item_t *array, int pos, int *value) |
626 | 0 | { |
627 | 0 | switch (try_get_mi_arr_param_int(array, pos, value)) |
628 | 0 | { |
629 | 0 | case MI_PARAM_ERR_MISSING: |
630 | 0 | LM_ERR("Array index out of bounds\n"); |
631 | 0 | break; |
632 | 0 | case MI_PARAM_ERR_ARR_BAD_TYPE: |
633 | 0 | LM_ERR("Array item is not an integer\n"); |
634 | 0 | break; |
635 | 0 | case 0: |
636 | 0 | return 0; |
637 | 0 | } |
638 | 0 | return -1; |
639 | 0 | } |
640 | | |
641 | | int try_get_mi_arr_param_object(const mi_item_t *array, int pos, |
642 | | mi_item_t **s) |
643 | 0 | { |
644 | 0 | if (!array) { |
645 | 0 | param_err_type = MI_PARAM_ERR_MISSING; |
646 | 0 | return MI_PARAM_ERR_MISSING; |
647 | 0 | } |
648 | | |
649 | 0 | *s = cJSON_GetArrayItem(array, pos); |
650 | 0 | if (!*s) { |
651 | 0 | param_err_type = MI_PARAM_ERR_MISSING; |
652 | 0 | return MI_PARAM_ERR_MISSING; |
653 | 0 | } |
654 | | |
655 | 0 | if (!((*s)->type & (cJSON_Object))) { |
656 | 0 | param_err_type = MI_PARAM_ERR_ARR_BAD_TYPE; |
657 | 0 | return MI_PARAM_ERR_ARR_BAD_TYPE; |
658 | 0 | } |
659 | | |
660 | 0 | return 0; |
661 | 0 | } |
662 | | |
663 | | int get_mi_arr_param_object(const mi_item_t *array, int pos, |
664 | | mi_item_t **s) |
665 | 0 | { |
666 | 0 | switch (try_get_mi_arr_param_object(array, pos, s)) |
667 | 0 | { |
668 | 0 | case MI_PARAM_ERR_MISSING: |
669 | 0 | LM_ERR("Array index out of bounds\n"); |
670 | 0 | break; |
671 | 0 | case MI_PARAM_ERR_ARR_BAD_TYPE: |
672 | 0 | LM_ERR("Bad data type for array item\n"); |
673 | 0 | break; |
674 | 0 | case 0: |
675 | 0 | return 0; |
676 | 0 | } |
677 | 0 | return -1; |
678 | 0 | } |
679 | | |
680 | | |
681 | | mi_response_t *init_mi_param_error(void) |
682 | 0 | { |
683 | 0 | char param_err_buf[MI_PARAM_ERR_BUFLEN]; |
684 | 0 | int len; |
685 | |
|
686 | 0 | switch (param_err_type) { |
687 | 0 | case MI_PARAM_ERR_BAD_TYPE: |
688 | 0 | len = snprintf(param_err_buf, MI_PARAM_ERR_BUFLEN, |
689 | 0 | "Bad type for parameter '%s'", param_err_pname); |
690 | 0 | if (len) |
691 | 0 | return init_mi_error_extra(JSONRPC_INVAL_PARAMS_CODE, |
692 | 0 | MI_SSTR(JSONRPC_INVAL_PARAMS_MSG), param_err_buf, len); |
693 | 0 | break; |
694 | 0 | case MI_PARAM_ERR_ARR_BAD_TYPE: |
695 | 0 | len = snprintf(param_err_buf, MI_PARAM_ERR_BUFLEN, |
696 | 0 | "Bad type for array item in parameter '%s'", param_err_pname); |
697 | 0 | if (len) |
698 | 0 | return init_mi_error_extra(JSONRPC_INVAL_PARAMS_CODE, |
699 | 0 | MI_SSTR(JSONRPC_INVAL_PARAMS_MSG), param_err_buf, len); |
700 | 0 | break; |
701 | 0 | case MI_PARAM_ERR_EMPTY_ARR: |
702 | 0 | len = snprintf(param_err_buf, MI_PARAM_ERR_BUFLEN, |
703 | 0 | "Empty array in parameter '%s'", param_err_pname); |
704 | 0 | if (len) |
705 | 0 | return init_mi_error_extra(JSONRPC_INVAL_PARAMS_CODE, |
706 | 0 | MI_SSTR(JSONRPC_INVAL_PARAMS_MSG), param_err_buf, len); |
707 | 0 | break; |
708 | 0 | case MI_PARAM_ERR_MISSING: |
709 | | /* the call has already been matched with one of the MI recipes so |
710 | | * treat a missing parameter as an unexpected server error (possibly |
711 | | * a bad param name was used by the handler when getting a param) */ |
712 | 0 | break; |
713 | 0 | } |
714 | | |
715 | 0 | return init_mi_error_extra(JSONRPC_SERVER_ERR_CODE, |
716 | 0 | MI_SSTR(JSONRPC_SERVER_ERR_MSG), MI_SSTR(ERR_DET_PARAM_HANDLE_S)); |
717 | 0 | } |