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