ims_qos: converted to the new module interface
[sip-router] / src / modules / jsonrpcs / jsonrpcs_mod.c
1 /**
2  * Copyright (C) 2014-2017 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35
36 #include "../../core/ver.h"
37 #include "../../core/trim.h"
38 #include "../../core/pt.h"
39 #include "../../core/sr_module.h"
40 #include "../../core/mod_fix.h"
41 #include "../../core/nonsip_hooks.h"
42 #include "../../core/cfg/cfg_struct.h"
43 #include "../../core/resolve.h"
44 #include "../../core/ip_addr.h"
45 #include "../../core/sip_msg_clone.h"
46 #include "../../core/data_lump.h"
47 #include "../../core/data_lump_rpl.h"
48 #include "../../core/kemi.h"
49 #include "../../modules/xhttp/api.h"
50
51 #include "jsonrpcs_mod.h"
52
53 /** @file
54  *
55  * This is the main file of jsonrpc-s module which contains all the functions
56  * related to http processing, as well as the module interface.
57  */
58
59 /** @addtogroup jsonrpc-s
60  * @ingroup modules
61  *
62  * <h1>Overview of Operation</h1>
63  * This module provides jsonrpc over http server implementation.
64  * @{
65  */
66
67 MODULE_VERSION
68
69
70 #define jsonrpc_malloc  pkg_malloc
71 #define jsonrpc_free    pkg_free
72
73 static str JSONRPC_REASON_OK = str_init("OK");
74 static str JSONRPC_CONTENT_TYPE_HTML = str_init("application/json");
75
76 /*!< 0 - all available; 1 - http; 2 - fifo; 4 - datagram */
77 static int jsonrpc_transport = 6; /* fifo + datagram */
78
79 static int jsonrpc_pretty_format = 1;
80
81 static int jsonrpc_register_rpc(void);
82
83 static int mod_init(void);
84 static int child_init(int rank);
85 static void mod_destroy(void);
86 static int jsonrpc_dispatch(sip_msg_t* msg, char* s1, char* s2);
87 static int jsonrpc_exec(sip_msg_t* msg, char* cmd, char* s2);
88
89 /* FIFO server parameters */
90 extern char *jsonrpc_fifo;                              /*!< FIFO file name */
91 extern char *jsonrpc_fifo_reply_dir;    /*!< dir where reply fifos are allowed */
92 extern int  jsonrpc_fifo_uid;                           /*!< Fifo default UID */
93 extern char *jsonrpc_fifo_uid_s;                        /*!< Fifo default User ID name */
94 extern int  jsonrpc_fifo_gid;                           /*!< Fifo default Group ID */
95 extern char *jsonrpc_fifo_gid_s;                        /*!< Fifo default Group ID name */
96 extern int  jsonrpc_fifo_mode; /* Default file mode rw-rw---- */
97 /* fifo function prototypes */
98 extern int jsonrpc_init_fifo_file(void);
99 extern int jsonrpc_fifo_mod_init(void);
100 extern int jsonrpc_fifo_child_init(int rank);
101 extern int jsonrpc_fifo_destroy(void);
102
103 /* DATAGRAM server parameters */
104 extern char *jsonrpc_dgram_socket;
105 extern int jsonrpc_dgram_workers;
106 extern int jsonrpc_dgram_timeout;
107 extern int  jsonrpc_dgram_unix_socket_uid;
108 extern char *jsonrpc_dgram_unix_socket_uid_s;
109 extern int  jsonrpc_dgram_unix_socket_gid;
110 extern char *jsonrpc_dgram_unix_socket_gid_s;
111 extern int jsonrpc_dgram_unix_socket_mode;
112 /* datagram function prototypes */
113 extern int jsonrpc_dgram_mod_init(void);
114 extern int jsonrpc_dgram_child_init(int rank);
115 extern int jsonrpc_dgram_destroy(void);
116
117 /** The context of the jsonrpc request being processed.
118  *
119  * This is a global variable that records the context of the jsonrpc request
120  * being currently processed.
121  * @sa rpc_ctx
122  */
123 static jsonrpc_ctx_t _jsonrpc_ctx_global;
124 static jsonrpc_ctx_t *_jsonrpc_ctx_active = NULL;
125
126 static xhttp_api_t xhttp_api;
127
128 /** Pointers to the functions that implement the RPC interface
129  * of jsonrpc module
130  */
131 static rpc_t func_param;
132
133 #define JSONRPC_ERROR_REASON_BUF_LEN    128
134 #define JSONRPC_PRINT_VALUE_BUF_LEN             1024
135
136 char jsonrpc_error_buf[JSONRPC_ERROR_REASON_BUF_LEN];
137
138 static cmd_export_t cmds[] = {
139         {"jsonrpc_dispatch", (cmd_function)jsonrpc_dispatch, 0, 0, 0,
140                 REQUEST_ROUTE},
141         {"jsonrpc_exec",     (cmd_function)jsonrpc_exec, 1, fixup_spve_null, 0,
142                 ANY_ROUTE},
143         {0, 0, 0, 0, 0, 0}
144 };
145
146 static param_export_t params[] = {
147         {"pretty_format",    PARAM_INT,    &jsonrpc_pretty_format},
148         {"transport",        PARAM_INT,    &jsonrpc_transport},
149         {"fifo_name",        PARAM_STRING, &jsonrpc_fifo},
150         {"fifo_mode",        PARAM_INT,    &jsonrpc_fifo_mode},
151         {"fifo_group",       PARAM_STRING, &jsonrpc_fifo_gid_s},
152         {"fifo_group",       PARAM_INT,    &jsonrpc_fifo_gid},
153         {"fifo_user",        PARAM_STRING, &jsonrpc_fifo_uid_s},
154         {"fifo_user",        PARAM_INT,    &jsonrpc_fifo_uid},
155         {"fifo_reply_dir",   PARAM_STRING, &jsonrpc_fifo_reply_dir},
156         {"dgram_socket",     PARAM_STRING, &jsonrpc_dgram_socket},
157         {"dgram_workers",    PARAM_INT,    &jsonrpc_dgram_workers},
158         {"dgram_timeout",    PARAM_INT,    &jsonrpc_dgram_timeout},
159         {"dgram_mode",       PARAM_INT,    &jsonrpc_dgram_unix_socket_mode},
160         {"dgram_group",      PARAM_STRING, &jsonrpc_dgram_unix_socket_gid_s},
161         {"dgram_group",      PARAM_INT,    &jsonrpc_dgram_unix_socket_gid},
162         {"dgram_user",       PARAM_STRING, &jsonrpc_dgram_unix_socket_uid_s},
163         {"dgram_user",       PARAM_INT,    &jsonrpc_dgram_unix_socket_uid},
164
165         {0, 0, 0}
166 };
167
168 static int jsonrpc_pv_get_jrpl(sip_msg_t *msg, pv_param_t *param, pv_value_t *res);
169 static int jsonrpc_pv_parse_jrpl_name(pv_spec_t *sp, str *in);
170
171 static pv_export_t mod_pvs[] = {
172         { {"jsonrpl",  sizeof("jsonrpl")-1}, PVT_OTHER,  jsonrpc_pv_get_jrpl,    0,
173                         jsonrpc_pv_parse_jrpl_name, 0, 0, 0 },
174         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
175 };
176
177 /** module exports */
178 struct module_exports exports= {
179         "jsonrpcs",
180         DEFAULT_DLFLAGS, /* dlopen flags */
181         cmds,
182         params,
183         0,                      /* exported statistics */
184         0,                      /* exported MI functions */
185         mod_pvs,        /* exported pseudo-variables */
186         0,                      /* extra processes */
187         mod_init,       /* module initialization function */
188         0,
189         mod_destroy,/* module destroy function */
190         child_init      /* per-child init function */
191 };
192
193
194 typedef struct jsonrpc_error {
195         int code;
196         str text;
197 } jsonrpc_error_t;
198
199 static jsonrpc_error_t _jsonrpc_error_table[] = {
200         { -32700, { "Parse Error", 11 } },
201         { -32600, { "Invalid Request", 15 } },
202         { -32601, { "Method Not Found", 16 } },
203         { -32602, { "Invalid Parameters", 18 } },
204         { -32603, { "Internal Error", 14 } },
205         { -32000, { "Execution Error", 15 } },
206         {0, { 0, 0 } }
207 };
208
209
210 static jsonrpc_plain_reply_t _jsonrpc_plain_reply;
211
212 jsonrpc_plain_reply_t* jsonrpc_plain_reply_get(void)
213 {
214         return &_jsonrpc_plain_reply;
215 }
216
217 static void jsonrpc_set_plain_reply(int rcode, str *rtext, str *rbody,
218                                         void (*free_fn)(void*))
219 {
220         if(_jsonrpc_plain_reply.rbody.s) {
221                 free_fn(_jsonrpc_plain_reply.rbody.s);
222         }
223         _jsonrpc_plain_reply.rcode = rcode;
224         _jsonrpc_plain_reply.rtext = *rtext;
225         if(rbody) {
226                 _jsonrpc_plain_reply.rbody = *rbody;
227         } else {
228                 _jsonrpc_plain_reply.rbody.s = NULL;
229                 _jsonrpc_plain_reply.rbody.len = 0;
230         }
231 }
232
233 static void jsonrpc_reset_plain_reply(void (*free_fn)(void*))
234 {
235         if(_jsonrpc_plain_reply.rbody.s) {
236                 free_fn(_jsonrpc_plain_reply.rbody.s);
237         }
238         memset(&_jsonrpc_plain_reply, 0, sizeof(jsonrpc_plain_reply_t));
239 }
240
241
242 /** Initialize jsonrpc reply data structure.
243  *
244  * This function initializes the data structure that contains all data related
245  * to the jsonrpc reply being created. The function must be called before any
246  * other function that adds data to the reply.
247  * @param ctx jsonrpc_ctx_t structure to be initialized.
248  * @return 0 on success, a negative number on error.
249  */
250 static int jsonrpc_init_reply(jsonrpc_ctx_t *ctx)
251 {
252         ctx->http_code = 200;
253         ctx->http_text = JSONRPC_REASON_OK;
254         ctx->jrpl = srjson_NewDoc(NULL);
255         if(ctx->jrpl==NULL) {
256                 LM_ERR("Failed to init the reply json document\n");
257                 return -1;
258         }
259         ctx->jrpl->root = srjson_CreateObject(ctx->jrpl);
260         if(ctx->jrpl->root==NULL) {
261                 LM_ERR("Failed to init the reply json root node\n");
262                 return -1;
263         }
264         srjson_AddStrStrToObject(ctx->jrpl, ctx->jrpl->root,
265                                         "jsonrpc", 7,
266                                         "2.0", 3);
267
268         return 0;
269 }
270
271
272 /** if this a delayed reply context,
273  * and it's never been use before, initialize it */
274 static int jsonrpc_delayed_reply_ctx_init(jsonrpc_ctx_t* ctx)
275 {
276         if  ((ctx->flags & JSONRPC_DELAYED_CTX_F)
277                         && (ctx->jrpl==0)) {
278                 if (jsonrpc_init_reply(ctx) < 0)
279                         return -1;
280                 jsonrpc_reset_plain_reply(ctx->jrpl->free_fn);
281                 _jsonrpc_ctx_active = ctx;
282         }
283         return 0;
284 }
285
286 /** Implementation of rpc_fault function required by the management API.
287  *
288  * This function will be called whenever a management function
289  * indicates that an error ocurred while it was processing the request. The
290  * function takes the reply code and reason phrase as parameters, these will
291  * be put in the body of the reply.
292  *
293  * @param ctx A pointer to the context structure of the request being
294  *            processed.
295  * @param code Reason code.
296  * @param fmt Formatting string used to build the reason phrase.
297  */
298 static void jsonrpc_fault(jsonrpc_ctx_t* ctx, int code, char* fmt, ...)
299 {
300         va_list ap;
301
302         jsonrpc_delayed_reply_ctx_init(ctx);
303
304         if(code <= 100) {
305                 ctx->http_code = 500;
306         } else {
307                 ctx->http_code = code;
308         }
309         va_start(ap, fmt);
310         vsnprintf(jsonrpc_error_buf, JSONRPC_ERROR_REASON_BUF_LEN, fmt, ap);
311         va_end(ap);
312         ctx->error_text.len = strlen(jsonrpc_error_buf);
313         ctx->error_text.s = jsonrpc_error_buf;
314         ctx->http_text.len = ctx->error_text.len;
315         ctx->http_text.s = jsonrpc_error_buf;
316         if(code == 0) {
317                 ctx->error_code = -32000;
318         } else {
319                 ctx->error_code = code;
320         }
321
322         return;
323 }
324
325
326 /** Implementation of rpc_send function required by the management API.
327  *
328  * This is the function that will be called whenever a management function
329  * asks the management interface to send the reply to the client.
330  * The SIP/HTTP reply sent to
331  * the client will be always 200 OK, if an error ocurred on the server then it
332  * will be indicated in the html document in body.
333  *
334  * @param ctx A pointer to the context structure of the jsonrpc request that
335  *            generated the reply.
336  * @return 1 if the reply was already sent, 0 on success, a negative number on
337  *            error
338  */
339 static int jsonrpc_send(jsonrpc_ctx_t* ctx)
340 {
341         srjson_t *nj = NULL;
342         int i;
343         str rbuf;
344
345         if (ctx->reply_sent) return 1;
346
347         ctx->reply_sent = 1;
348
349         if(ctx->error_code != 0) {
350                 /* fault handling */
351                 nj = srjson_CreateObject(ctx->jrpl);
352                 if(nj!=NULL) {
353                         srjson_AddNumberToObject(ctx->jrpl, nj, "code",
354                                         ctx->error_code);
355                         for(i=0; _jsonrpc_error_table[i].code!=0
356                                         && _jsonrpc_error_table[i].code!=ctx->error_code; i++);
357                         if(_jsonrpc_error_table[i].code!=0) {
358                                 srjson_AddStrStrToObject(ctx->jrpl, nj,
359                                         "message", 7,
360                                         _jsonrpc_error_table[i].text.s,
361                                         _jsonrpc_error_table[i].text.len);
362                         } else {
363                                 if(ctx->error_text.len>0) {
364                                         srjson_AddStrStrToObject(ctx->jrpl, nj,
365                                                         "message", 7,
366                                                         ctx->error_text.s, ctx->error_text.len);
367                                 } else {
368                                         srjson_AddStrStrToObject(ctx->jrpl, nj,
369                                                         "message", 7, "Unexpected Error", 16);
370                                 }
371                         }
372                         srjson_AddItemToObject(ctx->jrpl, ctx->jrpl->root, "error", nj);
373                 }
374         } else {
375                 nj = srjson_GetObjectItem(ctx->jrpl, ctx->jrpl->root, "result");
376                 if(nj==NULL) {
377                         if (!ctx->rpl_node) {
378                                 if(ctx->flags & RET_ARRAY) {
379                                         ctx->rpl_node = srjson_CreateArray(ctx->jrpl);
380                                 } else {
381                                         ctx->rpl_node = srjson_CreateObject(ctx->jrpl);
382                                 }
383                                 if(ctx->rpl_node == 0) {
384                                         LM_ERR("failed to create the root array node\n");
385                                 }
386                         }
387                         srjson_AddItemToObject(ctx->jrpl, ctx->jrpl->root,
388                                 "result", ctx->rpl_node);
389                         ctx->rpl_node = 0;
390                 }
391         }
392         if(ctx->jreq!=NULL && ctx->jreq->root!=NULL) {
393                 nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "id");
394                 if(nj!=NULL) {
395                         if(nj->valuestring!=NULL) {
396                                 srjson_AddStrStrToObject(ctx->jrpl, ctx->jrpl->root,
397                                                 "id", 2,
398                                                 nj->valuestring, strlen(nj->valuestring));
399                         } else {
400                                 srjson_AddNumberToObject(ctx->jrpl, ctx->jrpl->root, "id",
401                                                 nj->valuedouble);
402                         }
403                 }
404         } else {
405                 if(ctx->jsrid_type == 1) {
406                         srjson_AddStrStrToObject(ctx->jrpl, ctx->jrpl->root,
407                                         "id", 2,
408                                         ctx->jsrid_val, strlen(ctx->jsrid_val));
409                 } else if(ctx->jsrid_type == 2) {
410                         srjson_AddNumberToObject(ctx->jrpl, ctx->jrpl->root, "id",
411                                         (double)(*(long*)ctx->jsrid_val));
412                 }
413         }
414
415         if(jsonrpc_pretty_format==0) {
416                 rbuf.s = srjson_PrintUnformatted(ctx->jrpl, ctx->jrpl->root);
417         } else {
418                 rbuf.s = srjson_Print(ctx->jrpl, ctx->jrpl->root);
419         }
420         if(rbuf.s!=NULL) {
421                 rbuf.len = strlen(rbuf.s);
422         }
423         if (rbuf.s!=NULL) {
424                 LM_DBG("sending response with body: %p - %d %.*s\n", ctx->msg,
425                                 ctx->http_code, ctx->http_text.len, ctx->http_text.s);
426                 if(ctx->msg) {
427                         xhttp_api.reply(ctx->msg, ctx->http_code, &ctx->http_text,
428                                 &JSONRPC_CONTENT_TYPE_HTML, &rbuf);
429                 } else {
430                         jsonrpc_set_plain_reply(ctx->http_code, &ctx->http_text, &rbuf,
431                                         ctx->jrpl->free_fn);
432                         rbuf.s=NULL;
433                 }
434         } else {
435                 LM_DBG("sending response without body: %p - %d %.*s\n", ctx->msg,
436                                 ctx->http_code, ctx->http_text.len, ctx->http_text.s);
437                 if(ctx->msg) {
438                         xhttp_api.reply(ctx->msg, ctx->http_code, &ctx->http_text,
439                                         NULL, NULL);
440                 } else {
441                         jsonrpc_set_plain_reply(ctx->http_code, &ctx->http_text, NULL,
442                                         ctx->jrpl->free_fn);
443                 }
444         }
445         if (rbuf.s!=NULL) {
446                 ctx->jrpl->free_fn(rbuf.s);
447         }
448
449         return 0;
450 }
451
452
453 /** Converts the variables provided in parameter ap according to formatting
454  * string provided in parameter fmt into HTML format.
455  *
456  * This function takes the parameters provided in ap parameter and creates
457  * HTML formatted parameters that will be put in the html document.
458  * The format of input parameters is described in formatting string
459  * fmt which follows the syntax of the management API. In the case of
460  * an error the function will generate an error reply in err_reply parameter
461  * instead.
462  * @param ctx An error reply document will be generated here if the
463  *                  function encounters a problem while processing input
464  *                  parameters.
465  * @param fmt Formatting string of the management API.
466  * @param ap A pointer to the array of input parameters.
467  *
468  */
469 static srjson_t* jsonrpc_print_value(jsonrpc_ctx_t* ctx, char fmt, va_list* ap)
470
471 {
472         srjson_t *nj = NULL;
473         char buf[JSONRPC_PRINT_VALUE_BUF_LEN];
474         time_t dt;
475         struct tm* t;
476         str *sp;
477
478         switch(fmt) {
479         case 'd':
480                 nj = srjson_CreateNumber(ctx->jrpl, va_arg(*ap, int));
481                 break;
482         case 'u':
483                 nj = srjson_CreateNumber(ctx->jrpl, va_arg(*ap, unsigned int));
484                 break;
485         case 'f':
486                 nj = srjson_CreateNumber(ctx->jrpl, va_arg(*ap, double));
487                 break;
488         case 'b':
489                 nj = srjson_CreateBool(ctx->jrpl, ((va_arg(*ap, int)==0)?0:1));
490                 break;
491         case 't':
492                 dt = va_arg(*ap, time_t);
493                 t = gmtime(&dt);
494                 if (strftime(buf, JSONRPC_PRINT_VALUE_BUF_LEN,
495                                 "%Y%m%dT%H:%M:%S", t) == 0) {
496                         LM_ERR("Error while converting time\n");
497                         return NULL;
498                 }
499                 nj = srjson_CreateString(ctx->jrpl, buf);
500                 break;
501         case 's':
502                 nj = srjson_CreateString(ctx->jrpl, va_arg(*ap, char*));
503                 break;
504         case 'S':
505                 sp = va_arg(*ap, str*);
506                 nj = srjson_CreateStr(ctx->jrpl, sp->s, sp->len);
507                 break;
508         default:
509                 LM_ERR("Invalid formatting character [%c]\n", fmt);
510                 return NULL;
511         }
512         return nj;
513 }
514
515
516
517 /** Implementation of rpc_add function required by the management API.
518  *
519  * This function will be called when an RPC management function calls
520  * rpc->add to add a parameter to the jsonrpc reply being generated.
521  */
522 static int jsonrpc_add(jsonrpc_ctx_t* ctx, char* fmt, ...)
523 {
524         srjson_t *nj = NULL;
525         void **void_ptr;
526         va_list ap;
527
528         jsonrpc_delayed_reply_ctx_init(ctx);
529
530         va_start(ap, fmt);
531         while(*fmt) {
532                 if (*fmt == '{' || *fmt == '[') {
533                         void_ptr = va_arg(ap, void**);
534                         if (*fmt == '{') {
535                                 nj = srjson_CreateObject(ctx->jrpl);
536                         } else {
537                                 nj = srjson_CreateArray(ctx->jrpl);
538                         }
539                         *void_ptr = nj;
540                 } else {
541                         nj = jsonrpc_print_value(ctx, *fmt, &ap);
542                 }
543
544                 if(nj==NULL) goto err;
545                 if(ctx->flags & RET_ARRAY) {
546                         if (ctx->rpl_node==NULL) {
547                                 ctx->rpl_node = srjson_CreateArray(ctx->jrpl);
548                                 if(ctx->rpl_node == 0) {
549                                         LM_ERR("failed to create the root array node\n");
550                                         goto err;
551                                 }
552                         }
553                         srjson_AddItemToArray(ctx->jrpl, ctx->rpl_node, nj);
554                 } else {
555                         if (ctx->rpl_node) srjson_Delete(ctx->jrpl, ctx->rpl_node);
556                         ctx->rpl_node = nj;
557                 }
558
559                 fmt++;
560         }
561         va_end(ap);
562         return 0;
563 err:
564         va_end(ap);
565         return -1;
566 }
567
568
569 /** Implementation of rpc->scan function required by the management API.
570  *
571  * This is the function that will be called whenever a management function
572  * calls rpc->scan to get the value of parameter from the jsonrpc
573  * request. This function will extract the current parameter from the jsonrpc
574  * URL and attempts to convert it to the type requested by the management
575  * function that called it.
576  */
577 static int jsonrpc_scan(jsonrpc_ctx_t* ctx, char* fmt, ...)
578 {
579         int *int_ptr;
580         unsigned int *uint_ptr;
581         char **char_ptr;
582         double *double_ptr;
583         str *str_ptr;
584         int mandatory_param = 1;
585         int modifiers = 0;
586         int auto_convert = 0;
587         char* orig_fmt;
588         va_list ap;
589         str stmp;
590
591         if(ctx->req_node==NULL)
592                 return 0;
593
594         orig_fmt=fmt;
595         va_start(ap, fmt);
596         while(*fmt && ctx->req_node) {
597                 switch(*fmt) {
598                 case '*': /* start of optional parameters */
599                         mandatory_param = 0;
600                         modifiers++;
601                         fmt++;
602                         continue;
603                 case '.': /* autoconvert */
604                         modifiers++;
605                         fmt++;
606                         auto_convert = 1;
607                         continue;
608                 case 'b': /* Bool */
609                         uint_ptr = va_arg(ap, unsigned int*);
610                         *uint_ptr = SRJSON_GET_UINT(ctx->req_node);
611                         break;
612                 case 't': /* Date and time */
613                         uint_ptr = va_arg(ap, unsigned int*);
614                         *uint_ptr = SRJSON_GET_UINT(ctx->req_node);
615                         break;
616                 case 'd': /* Integer */
617                         int_ptr = va_arg(ap, int*);
618                         *int_ptr = SRJSON_GET_INT(ctx->req_node);
619                         break;
620                 case 'u': /* Unsigned Integer */
621                         uint_ptr = va_arg(ap, unsigned int*);
622                         *uint_ptr = SRJSON_GET_UINT(ctx->req_node);
623                         break;
624                 case 'f': /* double */
625                         double_ptr = va_arg(ap, double*);
626                         *double_ptr = ctx->req_node->valuedouble;
627                         break;
628                 case 's': /* zero terminated string */
629                         char_ptr = va_arg(ap, char**);
630                         if(ctx->req_node->type==srjson_String) {
631                                 *char_ptr = ctx->req_node->valuestring;
632                         } else if(auto_convert == 1) {
633                                 if(ctx->req_node->type==srjson_Number) {
634                                         *char_ptr = int2str(SRJSON_GET_ULONG(ctx->req_node),
635                                                         &stmp.len);
636                                 } else {
637                                         *char_ptr = NULL;
638                                         goto error;
639                                 }
640                         } else {
641                                 *char_ptr = NULL;
642                                 goto error;
643                         }
644                         break;
645                 case 'S': /* str structure */
646                         str_ptr = va_arg(ap, str*);
647                         if(ctx->req_node->type==srjson_String) {
648                                 str_ptr->s = ctx->req_node->valuestring;
649                                 str_ptr->len = strlen(ctx->req_node->valuestring);
650                         } else if(auto_convert == 1) {
651                                 if(ctx->req_node->type==srjson_Number) {
652                                         str_ptr->s = int2str(SRJSON_GET_ULONG(ctx->req_node),
653                                                         &str_ptr->len);
654                                 } else {
655                                         str_ptr->s = NULL;
656                                         str_ptr->len = 0;
657                                         goto error;
658                                 }
659                         } else {
660                                 str_ptr->s = NULL;
661                                 str_ptr->len = 0;
662                                 goto error;
663                         }
664                         break;
665                 case '{':
666                 case '[':
667                         LM_ERR("Unsupported param type '%c'\n", *fmt);
668                         jsonrpc_fault(ctx, 400, "Unsupported param type");
669                         goto error;
670                 default:
671                         LM_ERR("Invalid param type in formatting string: [%c]\n", *fmt);
672                         jsonrpc_fault(ctx, 500,
673                                 "Internal Server Error (inval formatting str)");
674                         goto error;
675                 }
676                 fmt++;
677                 auto_convert = 0;
678                 ctx->req_node = ctx->req_node->next;
679         }
680         /* error if there is still a scan char type and it is not optional */
681         if(*fmt && *fmt!='*' && mandatory_param==1)
682                 goto error;
683
684         va_end(ap);
685         return (int)(fmt-orig_fmt)-modifiers;
686 error:
687         va_end(ap);
688         return -((int)(fmt-orig_fmt)-modifiers);
689 }
690
691
692 /** Implementation of rpc_rpl_printf function required by the management API.
693  *
694  * This function will be called whenever an RPC management function calls
695  * rpc-printf to add a parameter to the jsonrpc reply being constructed.
696  */
697 static int jsonrpc_rpl_printf(jsonrpc_ctx_t* ctx, char* fmt, ...)
698 {
699         int n, buf_size;
700         char *buf = 0;
701         char tbuf[JSONRPC_PRINT_VALUE_BUF_LEN];
702         va_list ap;
703         srjson_t *nj = NULL;
704
705         jsonrpc_delayed_reply_ctx_init(ctx);
706
707         buf = tbuf;
708         buf_size = JSONRPC_PRINT_VALUE_BUF_LEN;
709         while (1) {
710                 /* try to print in the allocated space. */
711                 va_start(ap, fmt);
712                 n = vsnprintf(buf, buf_size, fmt, ap);
713                 va_end(ap);
714                 /* if that worked, return the string. */
715                 if (n > -1 && n < buf_size) {
716                         nj = srjson_CreateString(ctx->jrpl, buf);
717                         if(nj==NULL) {
718                                 LM_ERR("failed to create the value node\n");
719                                 if(buf && buf!=tbuf) jsonrpc_free(buf);
720                                 return -1;
721                         }
722                         if(ctx->flags & RET_ARRAY) {
723                                 if (ctx->rpl_node==NULL) {
724                                         ctx->rpl_node = srjson_CreateArray(ctx->jrpl);
725                                         if(ctx->rpl_node == 0) {
726                                                 LM_ERR("failed to create the root array node\n");
727                                                 if(buf && buf!=tbuf) jsonrpc_free(buf);
728                                                 return -1;
729                                         }
730                                 }
731                                 srjson_AddItemToArray(ctx->jrpl, ctx->rpl_node, nj);
732                         } else {
733                                 if (ctx->rpl_node) srjson_Delete(ctx->jrpl, ctx->rpl_node);
734                                 ctx->rpl_node = nj;
735                         }
736                         if(buf && buf!=tbuf) jsonrpc_free(buf);
737                         return 0;
738                 }
739                 /* else try again with more space. */
740                 if (n > -1) {   /* glibc 2.1 */
741                         buf_size = n + 1; /* precisely what is needed */
742                 } else {          /* glibc 2.0 */
743                         buf_size *= 2;  /* twice the old size */
744                 }
745                 if(buf && buf!=tbuf) jsonrpc_free(buf);
746                 if ((buf = jsonrpc_malloc(buf_size)) == 0) {
747                         jsonrpc_fault(ctx, 500, "Internal Server Error (No memory left)");
748                         LM_ERR("no memory left for rpc printf\n");
749                         return -1;
750                 }
751         }
752 }
753
754
755 /** Adds a new member to structure.
756  */
757 static int jsonrpc_struct_add(srjson_t *jnode, char* fmt, ...)
758 {
759         srjson_t *nj = NULL;
760         srjson_t *wj = NULL;
761         jsonrpc_ctx_t* ctx;
762         va_list ap;
763         void **void_ptr;
764         str mname;
765         int isobject;
766
767         if(jnode==NULL) {
768                 LM_ERR("invalid json node parameter\n");
769                 return -1;
770         }
771         if(jnode->type!=srjson_Object && jnode->type!=srjson_Array) {
772                 LM_ERR("json node parameter is not object or array (%d)\n",
773                                 jnode->type);
774                 return -1;
775         }
776         isobject = (jnode->type==srjson_Object);
777
778         ctx = _jsonrpc_ctx_active;
779         if(ctx==NULL || ctx->jrpl==NULL) {
780                 LM_ERR("reply object not initialized in rpl context %p - flags 0x%x\n",
781                                 ctx, (ctx)?ctx->flags:0);
782                 return -1;
783         }
784
785         va_start(ap, fmt);
786         while(*fmt) {
787                 mname.s = va_arg(ap, char*);
788                 mname.len = (mname.s?strlen(mname.s):0);
789                 if(mname.s==NULL) mname.s = "";
790
791                 if (*fmt == '{' || *fmt == '[') {
792                         void_ptr = va_arg(ap, void**);
793                         if (*fmt == '{') {
794                                 nj = srjson_CreateObject(ctx->jrpl);
795                         } else {
796                                 nj = srjson_CreateArray(ctx->jrpl);
797                         }
798                         *void_ptr = nj;
799                 } else {
800                         nj = jsonrpc_print_value(ctx, *fmt, &ap);
801                 }
802
803                 if(nj==NULL) {
804                         LM_ERR("failed to print the value (%c)\n", *fmt);
805                         goto err;
806                 }
807                 if(isobject) {
808                         /* add as member to object */
809                         srjson_AddItemToObject(ctx->jrpl, jnode, mname.s, nj);
810                 } else {
811                         /* wrap member in a new object and add to array */
812                         wj = srjson_CreateObject(ctx->jrpl);
813                         if(wj==NULL) {
814                                 LM_ERR("failed to create object (%c)\n", *fmt);
815                                 srjson_Delete(ctx->jrpl, nj);
816                                 goto err;
817                         }
818                         srjson_AddItemToObject(ctx->jrpl, wj, mname.s, nj);
819                         srjson_AddItemToArray(ctx->jrpl, jnode, wj);
820                 }
821                 fmt++;
822         }
823         va_end(ap);
824         return 0;
825 err:
826         va_end(ap);
827         return -1;
828 }
829
830
831 /** Adds a new member to structure.
832  */
833 static int jsonrpc_array_add(srjson_t *jnode, char* fmt, ...)
834 {
835         srjson_t *nj = NULL;
836         jsonrpc_ctx_t* ctx;
837         va_list ap;
838         void **void_ptr;
839
840         if(jnode==NULL) {
841                 LM_ERR("invalid json node parameter\n");
842                 return -1;
843         }
844         if(jnode->type!=srjson_Array) {
845                 LM_ERR("json node parameter is not array (%d)\n", jnode->type);
846                 return -1;
847         }
848
849         ctx = _jsonrpc_ctx_active;
850         if(ctx==NULL || ctx->jrpl==NULL) {
851                 LM_ERR("reply object not initialized in rpl context %p - flags 0x%x\n",
852                                 ctx, (ctx)?ctx->flags:0);
853                 return -1;
854         }
855
856         va_start(ap, fmt);
857         while(*fmt) {
858                 if (*fmt == '{' || *fmt == '[') {
859                         void_ptr = va_arg(ap, void**);
860                         if (*fmt == '{') {
861                                 nj = srjson_CreateObject(ctx->jrpl);
862                         } else {
863                                 nj = srjson_CreateArray(ctx->jrpl);
864                         }
865                         *void_ptr = nj;
866                 } else {
867                         nj = jsonrpc_print_value(ctx, *fmt, &ap);
868                 }
869
870                 if(nj==NULL) goto err;
871                 srjson_AddItemToArray(ctx->jrpl, jnode, nj);
872                 fmt++;
873         }
874         va_end(ap);
875         return 0;
876 err:
877         va_end(ap);
878         return -1;
879 }
880
881
882 static int jsonrpc_struct_scan(void* s, char* fmt, ...)
883 {
884         LM_ERR("Not implemented\n");
885         return -1;
886 }
887
888
889 /** Create a new member from formatting string and add it to a structure.
890  */
891 static int jsonrpc_struct_printf(srjson_t *jnode, char* mname, char* fmt, ...)
892 {
893         jsonrpc_ctx_t* ctx;
894         int n, buf_size;
895         char *buf = 0;
896         char tbuf[JSONRPC_PRINT_VALUE_BUF_LEN];
897         va_list ap;
898         srjson_t *nj = NULL;
899
900         if(jnode==NULL || mname==NULL) {
901                 LM_ERR("invalid json node or member name parameter (%p/%p)\n",
902                                 jnode, mname);
903                 return -1;
904         }
905         if(jnode->type!=srjson_Object) {
906                 LM_ERR("json node parameter is not object (%d)\n", jnode->type);
907                 return -1;
908         }
909
910         ctx = _jsonrpc_ctx_active;
911         if(ctx==NULL || ctx->jrpl==NULL) {
912                 LM_ERR("reply object not initialized in rpl context %p - flags 0x%x\n",
913                                 ctx, (ctx)?ctx->flags:0);
914                 return -1;
915         }
916
917         buf = tbuf;
918         buf_size = JSONRPC_PRINT_VALUE_BUF_LEN;
919         while (1) {
920                 /* try to print in the allocated space. */
921                 va_start(ap, fmt);
922                 n = vsnprintf(buf, buf_size, fmt, ap);
923                 va_end(ap);
924                 /* if that worked, return the string. */
925                 if (n > -1 && n < buf_size) {
926                         nj = srjson_CreateString(ctx->jrpl, buf);
927                         if(nj==NULL) {
928                                 LM_ERR("failed to create the value node\n");
929                                 if(buf && buf!=tbuf) jsonrpc_free(buf);
930                                 return -1;
931                         }
932                         srjson_AddItemToObject(ctx->jrpl, jnode, mname, nj);
933                         if(buf && buf!=tbuf) jsonrpc_free(buf);
934                         return 0;
935                 }
936                 /* else try again with more space. */
937                 if (n > -1) {   /* glibc 2.1 */
938                         buf_size = n + 1; /* precisely what is needed */
939                 } else {          /* glibc 2.0 */
940                         buf_size *= 2;  /* twice the old size */
941                 }
942                 if(buf && buf!=tbuf) jsonrpc_free(buf);
943                 if ((buf = jsonrpc_malloc(buf_size)) == 0) {
944                         jsonrpc_fault(ctx, 500, "Internal Server Error (No memory left)");
945                         LM_ERR("no memory left for rpc printf\n");
946                         return -1;
947                 }
948         }
949         return -1;
950 }
951
952
953 static void jsonrpc_clean_context(jsonrpc_ctx_t* ctx)
954 {
955         if (!ctx) return;
956         srjson_DeleteDoc(ctx->jreq);
957         if(ctx->rpl_node!=NULL) {
958                 srjson_Delete(ctx->jrpl, ctx->rpl_node);
959                 ctx->rpl_node = NULL;
960         }
961         srjson_DeleteDoc(ctx->jrpl);
962 }
963
964
965 /** Returns the RPC capabilities supported by the xmlrpc driver.
966  */
967 static rpc_capabilities_t jsonrpc_capabilities(jsonrpc_ctx_t* ctx)
968 {
969         /* support for async commands - delayed response */
970         return RPC_DELAYED_REPLY;
971 }
972
973
974 /** Returns a new "delayed reply" context.
975  * Creates a new delayed reply context in shm and returns it.
976  * @return 0 - not supported, already replied, or no more memory;
977  *         !=0 pointer to the special delayed ctx.
978  * Note1: one should use the returned ctx reply context to build a reply and
979  *  when finished call rpc_delayed_ctx_close().
980  * Note2: adding pieces to the reply in different processes is not supported.
981  */
982 static struct rpc_delayed_ctx* jsonrpc_delayed_ctx_new(jsonrpc_ctx_t* ctx)
983 {
984         struct rpc_delayed_ctx* ret;
985         int size;
986         jsonrpc_ctx_t* r_ctx;
987         sip_msg_t* shm_msg;
988         int len;
989         srjson_t *nj = NULL;
990
991         ret=0;
992         shm_msg=0;
993         len = 0;
994
995         if (ctx->reply_sent) {
996                 LM_ERR("response already sent - cannot create a delayed context\n");
997                 return 0; /* no delayed reply if already replied */
998         }
999
1000         if (ctx->transport!=JSONRPC_TRANS_HTTP) {
1001                 LM_ERR("delayed response implemented only for HTTP transport\n");
1002                 return 0;
1003         }
1004
1005         if(ctx->jreq==NULL || ctx->jreq->root==NULL) {
1006                 LM_ERR("invalid context attributes\n");
1007                 return 0;
1008         }
1009
1010         nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "id");
1011         if(nj==NULL) {
1012                 LM_ERR("id attribute is missing\n");
1013                 return 0;
1014         }
1015         if(nj->valuestring!=NULL && strlen(nj->valuestring)>JSONRPC_ID_SIZE-1) {
1016                 LM_ERR("id attribute is too long (%lu/%d)\n", strlen(nj->valuestring),
1017                                 JSONRPC_ID_SIZE);
1018                 return 0;
1019         }
1020         /* clone the sip msg */
1021         if(ctx->msg!=NULL) {
1022                 shm_msg=sip_msg_shm_clone(ctx->msg, &len, 1);
1023                 if (shm_msg==0)
1024                         goto error;
1025         }
1026
1027         /* alloc into one block */
1028         size=ROUND_POINTER(sizeof(*ret))+sizeof(jsonrpc_ctx_t);
1029         if ((ret=shm_malloc(size))==0)
1030                 goto error;
1031         memset(ret, 0, size);
1032         ret->rpc=func_param;
1033         ret->reply_ctx=(char*)ret+ROUND_POINTER(sizeof(*ret));
1034         r_ctx=ret->reply_ctx;
1035         r_ctx->flags=ctx->flags | JSONRPC_DELAYED_CTX_F;
1036         r_ctx->transport=ctx->transport;
1037         ctx->flags |= JSONRPC_DELAYED_REPLY_F;
1038         r_ctx->msg=shm_msg;
1039         r_ctx->msg_shm_block_size=len;
1040
1041         if(nj->valuestring!=NULL) {
1042                 strcpy(r_ctx->jsrid_val, nj->valuestring);
1043                 r_ctx->jsrid_type = 1;
1044         } else {
1045                 *(long*)r_ctx->jsrid_val = (long)nj->valuedouble;
1046                 r_ctx->jsrid_type = 2;
1047         }
1048
1049         return ret;
1050 error:
1051         if (shm_msg)
1052                 shm_free(shm_msg);
1053         if (ret)
1054                 shm_free(ret);
1055         return NULL;
1056 }
1057
1058
1059 /** Closes a "delayed reply" context and sends the reply.
1060  * If no reply has been sent the reply will be built and sent automatically.
1061  * See the notes from rpc_new_delayed_ctx()
1062  */
1063 static void jsonrpc_delayed_ctx_close(struct rpc_delayed_ctx* dctx)
1064 {
1065         jsonrpc_ctx_t* r_ctx;
1066         hdr_field_t* hdr;
1067
1068         r_ctx=dctx->reply_ctx;
1069         if (unlikely(!(r_ctx->flags & JSONRPC_DELAYED_CTX_F))){
1070                 BUG("reply ctx not marked as async/delayed\n");
1071                 goto error;
1072         }
1073
1074         if (jsonrpc_delayed_reply_ctx_init(r_ctx)<0)
1075                 goto error;
1076
1077         if (!r_ctx->reply_sent){
1078                 jsonrpc_send(r_ctx);
1079         }
1080 error:
1081         jsonrpc_clean_context(r_ctx);
1082         if(r_ctx->msg) {
1083                 /* free added lumps (rpc_send adds a body lump) */
1084                 del_nonshm_lump( &(r_ctx->msg->add_rm) );
1085                 del_nonshm_lump( &(r_ctx->msg->body_lumps) );
1086                 del_nonshm_lump_rpl( &(r_ctx->msg->reply_lump) );
1087                 /* free header's parsed structures
1088                  * that were added by failure handlers */
1089                 for( hdr=r_ctx->msg->headers ; hdr ; hdr=hdr->next ) {
1090                         if ( hdr->parsed && hdr_allocs_parse(hdr) &&
1091                                         (hdr->parsed<(void*)r_ctx->msg ||
1092                                         hdr->parsed>=(void*)(r_ctx->msg+r_ctx->msg_shm_block_size))) {
1093                                 /* header parsed filed doesn't point inside uas.request memory
1094                                  * chunck -> it was added by failure funcs.-> free it as pkg */
1095                                 DBG("removing hdr->parsed %d\n", hdr->type);
1096                                 clean_hdr_field(hdr);
1097                                 hdr->parsed = 0;
1098                         }
1099                 }
1100                 shm_free(r_ctx->msg);
1101         }
1102         r_ctx->msg=0;
1103         dctx->reply_ctx=0;
1104         shm_free(dctx);
1105         _jsonrpc_ctx_active = NULL;
1106
1107         return;
1108 }
1109
1110
1111 static int mod_init(void)
1112 {
1113         memset(&xhttp_api, 0, sizeof(xhttp_api_t));
1114
1115         /* bind the XHTTP API */
1116         if(jsonrpc_transport==0 || (jsonrpc_transport&1)) {
1117                 if (xhttp_load_api(&xhttp_api) < 0) {
1118                         if(jsonrpc_transport&1) {
1119                                 LM_ERR("cannot bind to XHTTP API\n");
1120                                 return -1;
1121                         } else {
1122                                 memset(&xhttp_api, 0, sizeof(xhttp_api_t));
1123                         }
1124                 }
1125         }
1126         /* prepare fifo transport */
1127         if(jsonrpc_transport==0 || (jsonrpc_transport&2)) {
1128                 if(jsonrpc_fifo != NULL && *jsonrpc_fifo!=0) {
1129                         LM_DBG("preparing to listen on fifo file: %s\n",
1130                                         jsonrpc_fifo);
1131                         if(jsonrpc_fifo_mod_init()<0) {
1132                                 if(jsonrpc_transport&2) {
1133                                         LM_ERR("cannot initialize fifo transport\n");
1134                                         return -1;
1135                                 } else {
1136                                         jsonrpc_fifo = NULL;
1137                                 }
1138                         }
1139                 } else {
1140                         jsonrpc_fifo = NULL;
1141                 }
1142         } else {
1143                 jsonrpc_fifo = NULL;
1144         }
1145         /* prepare datagram transport */
1146         if(jsonrpc_transport==0 || (jsonrpc_transport&4)) {
1147                 if(jsonrpc_dgram_socket!=NULL && *jsonrpc_dgram_socket!='\0') {
1148                         LM_DBG("preparing to listen on datagram socket: %s\n",
1149                                         jsonrpc_dgram_socket);
1150                         if(jsonrpc_dgram_mod_init()<0) {
1151                                 if(jsonrpc_transport&4) {
1152                                         LM_ERR("cannot initialize datagram transport\n");
1153                                         return -1;
1154                                 } else {
1155                                         jsonrpc_dgram_socket = NULL;
1156                                 }
1157                         }
1158                 } else {
1159                         jsonrpc_dgram_socket = NULL;
1160                 }
1161         } else {
1162                 jsonrpc_dgram_socket = NULL;
1163         }
1164
1165         memset(&func_param, 0, sizeof(func_param));
1166         func_param.send              = (rpc_send_f)jsonrpc_send;
1167         func_param.fault             = (rpc_fault_f)jsonrpc_fault;
1168         func_param.add               = (rpc_add_f)jsonrpc_add;
1169         func_param.scan              = (rpc_scan_f)jsonrpc_scan;
1170         func_param.rpl_printf        = (rpc_rpl_printf_f)jsonrpc_rpl_printf;
1171         func_param.struct_add        = (rpc_struct_add_f)jsonrpc_struct_add;
1172         func_param.array_add         = (rpc_struct_add_f)jsonrpc_array_add;
1173         func_param.struct_scan       = (rpc_struct_scan_f)jsonrpc_struct_scan;
1174         func_param.struct_printf     = (rpc_struct_printf_f)jsonrpc_struct_printf;
1175         func_param.capabilities      = (rpc_capabilities_f)jsonrpc_capabilities;
1176         func_param.delayed_ctx_new   = (rpc_delayed_ctx_new_f)jsonrpc_delayed_ctx_new;
1177         func_param.delayed_ctx_close =
1178                 (rpc_delayed_ctx_close_f)jsonrpc_delayed_ctx_close;
1179
1180         jsonrpc_register_rpc();
1181
1182         memset(&_jsonrpc_plain_reply, 0, sizeof(jsonrpc_plain_reply_t));
1183         return 0;
1184 }
1185
1186 static int child_init(int rank)
1187 {
1188         if (rank==PROC_MAIN) {
1189                 if(jsonrpc_fifo != NULL) {
1190                         if(jsonrpc_fifo_child_init(rank)<0) {
1191                                 LM_ERR("failed to init fifo worker\n");
1192                                 return -1;
1193                         }
1194                 }
1195                 if(jsonrpc_dgram_socket!=NULL) {
1196                         if(jsonrpc_dgram_child_init(rank)<0) {
1197                                 LM_ERR("failed to init datagram workers\n");
1198                                 return -1;
1199                         }
1200                 }
1201         }
1202
1203         return 0;
1204 }
1205
1206 /**
1207  *
1208  */
1209 static void mod_destroy(void)
1210 {
1211         jsonrpc_fifo_destroy();
1212         jsonrpc_dgram_destroy();
1213
1214         return;
1215 }
1216
1217 /**
1218  *
1219  */
1220 static int jsonrpc_dispatch(sip_msg_t* msg, char* s1, char* s2)
1221 {
1222         rpc_export_t* rpce;
1223         jsonrpc_ctx_t* ctx;
1224         int ret = 0;
1225         srjson_t *nj = NULL;
1226         str val;
1227
1228         if(!IS_HTTP(msg)) {
1229                 LM_DBG("Got non HTTP msg\n");
1230                 return NONSIP_MSG_PASS;
1231         }
1232
1233         if(xhttp_api.reply==NULL) {
1234                 LM_ERR("jsonrpc over http not initialized - check transport param\n");
1235                 return NONSIP_MSG_ERROR;
1236         }
1237
1238         /* initialize jsonrpc context */
1239         _jsonrpc_ctx_active = &_jsonrpc_ctx_global;
1240         ctx = _jsonrpc_ctx_active;
1241         memset(ctx, 0, sizeof(jsonrpc_ctx_t));
1242         ctx->msg = msg;
1243         /* parse the jsonrpc request */
1244         ctx->jreq = srjson_NewDoc(NULL);
1245         if(ctx->jreq==NULL) {
1246                 LM_ERR("Failed to init the json document\n");
1247                 return NONSIP_MSG_ERROR;
1248         }
1249
1250         ctx->jreq->buf.s = get_body(msg);
1251         ctx->jreq->buf.len = strlen(ctx->jreq->buf.s);
1252         ctx->jreq->root = srjson_Parse(ctx->jreq, ctx->jreq->buf.s);
1253         if(ctx->jreq->root == NULL)
1254         {
1255                 LM_ERR("invalid json doc [[%s]]\n", ctx->jreq->buf.s);
1256                 return NONSIP_MSG_ERROR;
1257         }
1258         ctx->transport = JSONRPC_TRANS_HTTP;
1259         if (jsonrpc_init_reply(ctx) < 0) goto send_reply;
1260
1261         /* sanity checks on jsonrpc request */
1262         nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "jsonrpc");
1263         if(nj==NULL || nj->valuestring==NULL) {
1264                 LM_ERR("missing or invalid jsonrpc field in request\n");
1265                 goto send_reply;
1266         }
1267         val.s = nj->valuestring;
1268         val.len = strlen(val.s);
1269         if(val.len!=3 || strncmp(val.s, "2.0", 3)!=0) {
1270                 LM_ERR("unsupported jsonrpc version [%.*s]\n", val.len, val.s);
1271                 goto send_reply;
1272         }
1273         /* run jsonrpc command */
1274         nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "method");
1275         if(nj==NULL || nj->valuestring==NULL) {
1276                 LM_ERR("missing or invalid jsonrpc method field in request\n");
1277                 goto send_reply;
1278         }
1279         val.s = nj->valuestring;
1280         val.len = strlen(val.s);
1281         ctx->method = val.s;
1282         rpce = find_rpc_export(ctx->method, 0);
1283         if (!rpce || !rpce->function) {
1284                 LM_ERR("method callback not found [%.*s]\n", val.len, val.s);
1285                 jsonrpc_fault(ctx, 500, "Method Not Found");
1286                 goto send_reply;
1287         }
1288         ctx->flags = rpce->flags;
1289         nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "params");
1290         if(nj!=NULL && nj->type!=srjson_Array && nj->type!=srjson_Object) {
1291                 LM_ERR("params field is not an array or object\n");
1292                 goto send_reply;
1293         }
1294         if(nj!=NULL) ctx->req_node = nj->child;
1295         rpce->function(&func_param, ctx);
1296
1297 send_reply:
1298         if (!ctx->reply_sent && !(ctx->flags&JSONRPC_DELAYED_REPLY_F)) {
1299                 ret = jsonrpc_send(ctx);
1300         }
1301         jsonrpc_clean_context(ctx);
1302         if (ret < 0) return -1;
1303         return 1;
1304 }
1305
1306
1307 int jsonrpc_exec_ex(str *cmd, str *rpath)
1308 {
1309         rpc_export_t* rpce;
1310         jsonrpc_ctx_t* ctx;
1311         int ret;
1312         srjson_t *nj = NULL;
1313         str val;
1314         str scmd;
1315
1316         scmd = *cmd;
1317
1318         /* initialize jsonrpc context */
1319         _jsonrpc_ctx_active = &_jsonrpc_ctx_global;
1320         ctx = _jsonrpc_ctx_active;
1321         memset(ctx, 0, sizeof(jsonrpc_ctx_t));
1322         ctx->msg = NULL; /* mark it not send a reply out */
1323         /* parse the jsonrpc request */
1324         ctx->jreq = srjson_NewDoc(NULL);
1325         if(ctx->jreq==NULL) {
1326                 LM_ERR("Failed to init the json document\n");
1327                 return -1;
1328         }
1329         ctx->jreq->buf = scmd;
1330         ctx->jreq->root = srjson_Parse(ctx->jreq, ctx->jreq->buf.s);
1331         if(ctx->jreq->root == NULL) {
1332                 LM_ERR("invalid json doc [[%.*s]]\n",
1333                                 ctx->jreq->buf.len, ctx->jreq->buf.s);
1334                 return -1;
1335         }
1336         ret = -1;
1337         if (jsonrpc_init_reply(ctx) < 0) goto send_reply;
1338         jsonrpc_reset_plain_reply(ctx->jrpl->free_fn);
1339
1340
1341         /* sanity checks on jsonrpc request */
1342         nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "jsonrpc");
1343         if(nj==NULL) {
1344                 LM_ERR("missing jsonrpc field in request\n");
1345                 goto send_reply;
1346         }
1347         val.s = nj->valuestring;
1348         val.len = strlen(val.s);
1349         if(val.len!=3 || strncmp(val.s, "2.0", 3)!=0) {
1350                 LM_ERR("unsupported jsonrpc version [%.*s]\n", val.len, val.s);
1351                 goto send_reply;
1352         }
1353         /* reply name */
1354         if(rpath!=NULL) {
1355                 if(rpath->s==NULL || rpath->len<=0) {
1356                         LM_ERR("empty buffer to store the reply name\n");
1357                         goto send_reply;
1358                 }
1359                 nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "reply_name");
1360                 if(nj==NULL) {
1361                         LM_ERR("missing reply_name field in request\n");
1362                         goto send_reply;
1363                 }
1364                 val.s = nj->valuestring;
1365                 val.len = strlen(val.s);
1366                 if(val.len>=rpath->len) {
1367                         LM_ERR("no space to store reply_name field\n");
1368                         goto send_reply;
1369                 }
1370                 strncpy(rpath->s, val.s, val.len);
1371                 rpath->s[val.len] = 0;
1372                 rpath->len = val.len;
1373         }
1374         /* run jsonrpc command */
1375         nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "method");
1376         if(nj==NULL) {
1377                 LM_ERR("missing jsonrpc method field in request\n");
1378                 goto send_reply;
1379         }
1380         val.s = nj->valuestring;
1381         val.len = strlen(val.s);
1382         ctx->method = val.s;
1383         rpce = find_rpc_export(ctx->method, 0);
1384         if (!rpce || !rpce->function) {
1385                 LM_ERR("method callback not found [%.*s]\n", val.len, val.s);
1386                 jsonrpc_fault(ctx, 500, "Method Not Found");
1387                 goto send_reply;
1388         }
1389         ctx->flags = rpce->flags;
1390         nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "params");
1391         if(nj!=NULL && nj->type!=srjson_Array && nj->type!=srjson_Object) {
1392                 LM_ERR("params field is not an array or object\n");
1393                 goto send_reply;
1394         }
1395         if(nj!=NULL) ctx->req_node = nj->child;
1396         rpce->function(&func_param, ctx);
1397         ret = 1;
1398
1399 send_reply:
1400         if (!ctx->reply_sent) {
1401                 ret = jsonrpc_send(ctx);
1402         }
1403         jsonrpc_clean_context(ctx);
1404         if (ret < 0) return -1;
1405         return 1;
1406 }
1407
1408 static int jsonrpc_exec(sip_msg_t* msg, char* cmd, char* s2)
1409 {
1410         str scmd;
1411
1412         if(fixup_get_svalue(msg, (gparam_t*)cmd, &scmd)<0 || scmd.len<=0) {
1413                 LM_ERR("cannot get the rpc command parameter\n");
1414                 return -1;
1415         }
1416         return jsonrpc_exec_ex(&scmd, NULL);
1417 }
1418 /**
1419  *
1420  */
1421 static const char* jsonrpc_rpc_echo_doc[2] = {
1422         "Sample echo command",
1423         0
1424 };
1425
1426 /**
1427  *
1428  */
1429 static void jsonrpc_rpc_echo(rpc_t* rpc, void* ctx)
1430 {
1431         str sval = {"", 0};
1432         int ival = 0;
1433
1434         if(rpc->scan(ctx, "*.S", &sval)>0) {
1435                 LM_DBG("READ STR: %.*s\n", sval.len, sval.s);
1436                 rpc->add(ctx, "S", &sval);
1437                 if(rpc->scan(ctx, "*.d", &ival)>0) {
1438                         LM_DBG("READ INT: %d\n", ival);
1439                         rpc->add(ctx, "d", ival);
1440                 }
1441         } else {
1442                 LM_DBG("no parameters\n");
1443         }
1444 }
1445 /**
1446  *
1447  */
1448 static rpc_export_t jsonrpc_rpc[] = {
1449         {"jsonrpc.echo", jsonrpc_rpc_echo,  jsonrpc_rpc_echo_doc,       RET_ARRAY},
1450         {0, 0, 0, 0}
1451 };
1452
1453 /**
1454  *
1455  */
1456 static int jsonrpc_register_rpc(void)
1457 {
1458         if (rpc_register_array(jsonrpc_rpc)!=0)
1459         {
1460                 LM_ERR("failed to register RPC commands\n");
1461                 return -1;
1462         }
1463         return 0;
1464 }
1465
1466 /**
1467  *
1468  */
1469 static int jsonrpc_pv_get_jrpl(sip_msg_t *msg, pv_param_t *param, pv_value_t *res)
1470 {
1471         switch(param->pvn.u.isname.name.n)
1472         {
1473                 case 0:
1474                         return pv_get_uintval(msg, param, res,
1475                                         (unsigned int)_jsonrpc_plain_reply.rcode);
1476                 case 1:
1477                         if(_jsonrpc_plain_reply.rtext.s==NULL)
1478                                 return pv_get_null(msg, param, res);
1479                         return pv_get_strval(msg, param, res, &_jsonrpc_plain_reply.rtext);
1480                 case 2:
1481                         if(_jsonrpc_plain_reply.rbody.s==NULL)
1482                                 return pv_get_null(msg, param, res);
1483                         return pv_get_strval(msg, param, res, &_jsonrpc_plain_reply.rbody);
1484                 default:
1485                         return pv_get_null(msg, param, res);
1486         }
1487 }
1488
1489 /**
1490  *
1491  */
1492 static int jsonrpc_pv_parse_jrpl_name(pv_spec_t *sp, str *in)
1493 {
1494         if(in->len!=4) {
1495                 LM_ERR("unknown inner name [%.*s]\n", in->len, in->s);
1496                 return -1;
1497         }
1498         if(strncmp(in->s, "code", 4)==0) {
1499                 sp->pvp.pvn.u.isname.name.n = 0;
1500         } else if(strncmp(in->s, "text", 4)==0) {
1501                 sp->pvp.pvn.u.isname.name.n = 1;
1502         } else if(strncmp(in->s, "body", 4)==0) {
1503                 sp->pvp.pvn.u.isname.name.n = 2;
1504         } else {
1505                 LM_ERR("unknown inner name [%.*s]\n", in->len, in->s);
1506                 return -1;
1507         }
1508         return 0;
1509 }
1510
1511 /**
1512  *
1513  */
1514 static int ki_jsonrpcs_exec(sip_msg_t *msg, str *scmd)
1515 {
1516         return jsonrpc_exec_ex(scmd, NULL);
1517 }
1518
1519 /**
1520  *
1521  */
1522 /* clang-format off */
1523 static sr_kemi_t sr_kemi_jsonrpcs_exports[] = {
1524         { str_init("jsonrpcs"), str_init("exec"),
1525                 SR_KEMIP_INT, ki_jsonrpcs_exec,
1526                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1527                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1528         },
1529
1530         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
1531 };
1532 /* clang-format on */
1533
1534 /**
1535  *
1536  */
1537 int mod_register(char *path, int *dlflags, void *p1, void *p2)
1538 {
1539         sr_kemi_modules_add(sr_kemi_jsonrpcs_exports);
1540         return 0;
1541 }
1542
1543 /** @} */