00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024
00025 #include "../../sr_module.h"
00026 #include "../../dprint.h"
00027
00028 #include "../../lib/kmi/mi.h"
00029 #include "../../rpc.h"
00030 #include "../../lib/binrpc/binrpc_api.h"
00031
00032 MODULE_VERSION
00033
00034 static int child_init(int rank);
00035 static int mod_init(void);
00036
00037 static str mi_rpc_indent = { "\t", 1 };
00038 static char *rpc_url = "";
00039
00040 static const char* rpc_mi_exec_doc[2] = {
00041 "Execute MI command",
00042 0
00043 };
00044
00045 static param_export_t parameters[] = {
00046 {"rpc_url", STR_PARAM, &rpc_url},
00047 {0, 0, 0}
00048 };
00049
00050 enum mi_rpc_print_mode {
00051 MI_PRETTY_PRINT,
00052 MI_FIFO_PRINT,
00053 MI_DATAGRAM_PRINT,
00054 MI_XMLRPC_PRINT
00055 };
00056
00057
00058
00059 static void rpc_mi_pretty_exec(rpc_t* rpc, void* c);
00060 static void rpc_mi_fifo_exec(rpc_t* rpc, void* c);
00061 static void rpc_mi_dg_exec(rpc_t* rpc, void* c);
00062 static void rpc_mi_xmlrpc_exec(rpc_t* rpc, void* c);
00063
00064 rpc_export_t mr_rpc[] = {
00065 {"mi", rpc_mi_pretty_exec, rpc_mi_exec_doc, RET_ARRAY},
00066 {"mi_fifo", rpc_mi_fifo_exec, rpc_mi_exec_doc, RET_ARRAY},
00067 {"mi_dg", rpc_mi_dg_exec, rpc_mi_exec_doc, RET_ARRAY},
00068 {"mi_xmlrpc", rpc_mi_xmlrpc_exec, rpc_mi_exec_doc, RET_ARRAY},
00069 {0, 0, 0, 0}
00070 };
00071
00072 struct module_exports exports = {
00073 "mi_rpc",
00074 0,
00075 mr_rpc,
00076 parameters,
00077 mod_init,
00078 0,
00079 0,
00080 0,
00081 child_init
00082 };
00083
00084 static struct mi_root* mi_run_rpc(struct mi_root* cmd_tree, void* param);
00085
00086 static mi_export_t mi_cmds[] =
00087 {
00088 { "rpc", mi_run_rpc, 0, 0, 0,},
00089 { 0, 0, 0, 0, 0 }
00090 };
00091
00092
00093 static int mod_init(void)
00094 {
00095 if(register_mi_mod(exports.name, mi_cmds)!=0)
00096 {
00097 LM_ERR("Failed to register MI commands\n");
00098 return(-1);
00099 }
00100 return 0;
00101 }
00102
00103 static int child_init(int rank)
00104 {
00105 if(is_rpc_worker(rank)) {
00106 LM_DBG("initializing child[%d] for rpc handling\n", rank);
00107 if(init_mi_child(rank, 0)!=0) {
00108 LM_CRIT("Failed to init the mi commands\n");
00109 return -1;
00110 }
00111 }
00112
00113 return 0;
00114 }
00115
00116 struct mi_root *mi_rpc_read_params(rpc_t *rpc, void *ctx)
00117 {
00118 struct mi_root *root;
00119 struct mi_node *node;
00120 str name;
00121 str value;
00122
00123 root = init_mi_tree(0,0,0);
00124 if (!root) {
00125 LM_ERR("the MI tree cannot be initialized!\n");
00126 goto error;
00127 }
00128 node = &root->node;
00129
00130 while (rpc->scan(ctx, "*.S", &value) == 1)
00131 {
00132 name.s = 0;
00133 name.len = 0;
00134
00135 if(value.len>=2 && value.s[0]=='-' && value.s[1]=='-')
00136 {
00137
00138 if(value.len>2)
00139 {
00140 name.s = value.s + 2;
00141 name.len = value.len - 2;
00142 }
00143
00144
00145 if(rpc->scan(ctx, "*.S", &value) != 1)
00146 {
00147 LM_ERR("value expected\n");
00148 goto error;
00149 }
00150 }
00151
00152 if(!add_mi_node_child(node, 0, name.s, name.len,
00153 value.s, value.len))
00154 {
00155 LM_ERR("cannot add the child node to the MI tree\n");
00156 goto error;
00157 }
00158 }
00159
00160 return root;
00161
00162 error:
00163 if (root)
00164 free_mi_tree(root);
00165 return 0;
00166 }
00167
00168
00169
00173 static int mi_rpc_print_node(rpc_t* rpc, void* ctx, struct mi_node* node,
00174 enum mi_rpc_print_mode mode, char* prefix)
00175 {
00176 static char buf[512];
00177 char* p;
00178 int n;
00179 int size;
00180 struct mi_attr *attr;
00181
00182 p=buf;
00183 *p=0;
00184 size=sizeof(buf);
00185 n=snprintf(p, size, "%s%.*s:: %.*s",
00186 prefix,
00187 node->name.len, (node->name.s)?node->name.s:"",
00188 node->value.len, (node->value.s)?node->value.s:"");
00189 if (n==-1 || n >= size)
00190 goto error_buf;
00191 p+=n;
00192 size-=n;
00193 for( attr=node->attributes ; attr!=NULL ; attr=attr->next ) {
00194 n=snprintf(p, size, " %.*s=%.*s",
00195 attr->name.len, (attr->name.s)?attr->name.s:"",
00196 attr->value.len, (attr->value.s)?attr->value.s:"");
00197 if (n==-1 || n >= size)
00198 goto error_buf;
00199 p+=n;
00200 size-=n;
00201 }
00202 if (mode!=MI_PRETTY_PRINT){
00203 n=snprintf(p, size, "\n");
00204 if (n==-1 || n>= size )
00205 goto error_buf;
00206 }
00207 rpc->add(ctx, "s", buf);
00208 return 0;
00209 error_buf:
00210 ERR("line too long (extra %d chars)\n", (n>=size)?n-size+1:0);
00211 rpc->fault(ctx, 500, "Line too long");
00212 return -1;
00213 }
00214
00215
00216
00217 static int mi_rpc_rprint_all(rpc_t* rpc, void* ctx, struct mi_node *node,
00218 enum mi_rpc_print_mode mode, int level)
00219 {
00220 char indent[32];
00221 int i;
00222 char *p;
00223
00224 p = indent;
00225 switch(mode){
00226 case MI_FIFO_PRINT:
00227 case MI_DATAGRAM_PRINT:
00228 case MI_PRETTY_PRINT:
00229 if(level*mi_rpc_indent.len>=32)
00230 {
00231 LM_ERR("too many recursive levels for indentation\n");
00232 return -1;
00233 }
00234 for(i=0; i<level; i++)
00235 {
00236 memcpy(p, mi_rpc_indent.s, mi_rpc_indent.len);
00237 p += mi_rpc_indent.len;
00238 }
00239 break;
00240 case MI_XMLRPC_PRINT:
00241
00242 break;
00243 }
00244 *p = 0;
00245 for( ; node ; node=node->next )
00246 {
00247 if (mi_rpc_print_node(rpc, ctx, node, mode, p)<0)
00248 return -1;
00249 if (node->kids) {
00250 if (mi_rpc_rprint_all(rpc, ctx, node->kids, mode, level+1)<0)
00251 return -1;
00252 }
00253 }
00254 return 0;
00255 }
00256
00257
00258
00264 static int mi_rpc_print_tree(rpc_t* rpc, void* ctx, struct mi_root *tree,
00265 enum mi_rpc_print_mode mode)
00266 {
00267 switch(mode){
00268 case MI_FIFO_PRINT:
00269 case MI_DATAGRAM_PRINT:
00270
00271 rpc->printf(ctx, "%d %.*s\n", tree->code,
00272 tree->reason.len, tree->reason.s);
00273 break;
00274 case MI_PRETTY_PRINT:
00275 case MI_XMLRPC_PRINT:
00276
00277 if (tree->code<200 || tree->code> 299) {
00278 rpc->fault(ctx, tree->code, tree->reason.s);
00279 return -1;
00280 }
00281 break;
00282 }
00283
00284 if (tree->node.kids)
00285 {
00286 if (mi_rpc_rprint_all(rpc, ctx, tree->node.kids, mode, 0)<0)
00287 return -1;
00288 }
00289 if (mode==MI_FIFO_PRINT){
00290
00291 rpc->printf(ctx, "\n");
00292 }
00293
00294 return 0;
00295 }
00296
00297
00298
00299
00300 struct mi_rpc_handler_param{
00301 rpc_delayed_ctx_t* dctx;
00302 enum mi_rpc_print_mode mode;
00303 };
00304
00305
00306 static void mi_rpc_async_close(struct mi_root* mi_rpl,
00307 struct mi_handler* mi_h,
00308 int done)
00309 {
00310 rpc_delayed_ctx_t* dctx;
00311 rpc_t* rpc;
00312 void* c;
00313 enum mi_rpc_print_mode mode;
00314
00315 dctx=0;
00316 if (done){
00317 if (mi_h->param==0){
00318 BUG("null param\n");
00319 shm_free(mi_h);
00320 goto error;
00321 }
00322 dctx=((struct mi_rpc_handler_param*)mi_h->param)->dctx;
00323 if (dctx==0){
00324 BUG("null dctx\n");
00325 shm_free(mi_h->param);
00326 shm_free(mi_h);
00327 mi_h->param=0;
00328 goto error;
00329 }
00330 mode=((struct mi_rpc_handler_param*)mi_h->param)->mode;
00331 rpc=&dctx->rpc;
00332 c=dctx->reply_ctx;
00333
00334 mi_rpc_print_tree(rpc, c, mi_rpl, mode);
00335
00336 rpc->delayed_ctx_close(dctx);
00337 shm_free(mi_h->param);
00338 mi_h->param=0;
00339 shm_free(mi_h);
00340 }
00341 error:
00342 if (mi_rpl)
00343 free_mi_tree(mi_rpl);
00344 return;
00345 }
00346
00347
00348
00349 static void rpc_mi_exec(rpc_t *rpc, void *ctx, enum mi_rpc_print_mode mode)
00350 {
00351 str cmd;
00352 struct mi_cmd *mic;
00353 struct mi_root *mi_req;
00354 struct mi_root *mi_rpl;
00355 struct mi_handler* mi_async_h;
00356 struct mi_rpc_handler_param* mi_handler_param;
00357
00358 if (rpc->scan(ctx, "S", &cmd) < 1)
00359 {
00360 LM_ERR("command parameter not found\n");
00361 rpc->fault(ctx, 500, "command parameter missing");
00362 return;
00363 }
00364
00365 mi_async_h=0;
00366 mi_req = 0;
00367 mi_rpl=0;
00368
00369 mic = lookup_mi_cmd(cmd.s, cmd.len);
00370 if(mic==0)
00371 {
00372 LM_ERR("mi command %.*s is not available\n", cmd.len, cmd.s);
00373 rpc->fault(ctx, 500, "command not available");
00374 return;
00375 }
00376
00377 if (mic->flags&MI_ASYNC_RPL_FLAG)
00378 {
00379 if (rpc->capabilities==0 ||
00380 !(rpc->capabilities(ctx) & RPC_DELAYED_REPLY))
00381 {
00382 rpc->fault(ctx, 500,
00383 "this rpc transport does not support async mode");
00384 return;
00385 }
00386 }
00387
00388 if(!(mic->flags&MI_NO_INPUT_FLAG))
00389 {
00390 mi_req = mi_rpc_read_params(rpc, ctx);
00391 if(mi_req==NULL)
00392 {
00393 LM_ERR("cannot parse parameters\n");
00394 rpc->fault(ctx, 500, "cannot parse parameters");
00395 goto error;
00396 }
00397 if (mic->flags&MI_ASYNC_RPL_FLAG)
00398 {
00399
00400 mi_handler_param=shm_malloc(sizeof(*mi_handler_param));
00401 if (mi_handler_param==0){
00402 rpc->fault(ctx, 500, "out of memory");
00403 return;
00404 }
00405 mi_async_h=shm_malloc(sizeof(*mi_async_h));
00406 if (mi_async_h==0){
00407 shm_free(mi_handler_param);
00408 mi_handler_param=0;
00409 rpc->fault(ctx, 500, "out of memory");
00410 return;
00411 }
00412 memset(mi_async_h, 0, sizeof(*mi_async_h));
00413 mi_async_h->handler_f=mi_rpc_async_close;
00414 mi_handler_param->mode=mode;
00415 mi_handler_param->dctx=rpc->delayed_ctx_new(ctx);
00416 if (mi_handler_param->dctx==0){
00417 rpc->fault(ctx, 500, "internal error: async ctx"
00418 " creation failed");
00419 goto error;
00420 }
00421
00422
00423 rpc=&mi_handler_param->dctx->rpc;
00424 ctx=mi_handler_param->dctx->reply_ctx;
00425 mi_async_h->param=mi_handler_param;
00426 }
00427 mi_req->async_hdl=mi_async_h;
00428 }
00429 mi_rpl=run_mi_cmd(mic, mi_req);
00430
00431 if(mi_rpl == 0)
00432 {
00433 rpc->fault(ctx, 500, "execution failed");
00434 goto error;
00435 }
00436
00437 if (mi_rpl!=MI_ROOT_ASYNC_RPL)
00438 {
00439 mi_rpc_print_tree(rpc, ctx, mi_rpl, mode);
00440 goto end;
00441 }else if (mi_async_h==0){
00442
00443 rpc->fault(ctx, 500, "bad mi command: unexpected async reply");
00444 goto error;
00445 }
00446 mi_async_h=0;
00447 end:
00448 error:
00449 if (mi_req)
00450 free_mi_tree(mi_req);
00451 if (mi_rpl && mi_rpl!=MI_ROOT_ASYNC_RPL)
00452 free_mi_tree(mi_rpl);
00453 if (mi_async_h){
00454 if (mi_async_h->param){
00455 if (((struct mi_rpc_handler_param*)mi_async_h->param)->dctx)
00456 rpc->delayed_ctx_close(((struct mi_rpc_handler_param*)
00457 mi_async_h->param)->dctx);
00458 shm_free(mi_async_h->param);
00459 }
00460 shm_free(mi_async_h);
00461 }
00462 return;
00463 }
00464
00465
00466
00467 static void rpc_mi_pretty_exec(rpc_t* rpc, void* c)
00468 {
00469 rpc_mi_exec(rpc, c, MI_PRETTY_PRINT);
00470 }
00471
00472
00473
00474 static void rpc_mi_fifo_exec(rpc_t* rpc, void* c)
00475 {
00476 rpc_mi_exec(rpc, c, MI_FIFO_PRINT);
00477 }
00478
00479
00480
00481 static void rpc_mi_dg_exec(rpc_t* rpc, void* c)
00482 {
00483 rpc_mi_exec(rpc, c, MI_DATAGRAM_PRINT);
00484 }
00485
00486
00487
00488 static void rpc_mi_xmlrpc_exec(rpc_t* rpc, void* c)
00489 {
00490 rpc_mi_exec(rpc, c, MI_XMLRPC_PRINT);
00491 }
00492
00493
00494 static struct mi_root* mi_run_rpc(struct mi_root* cmd_tree, void* param)
00495 {
00496 const char* FAILED = "Failed";
00497 const char* CONNECT_FAILED = "Connection to RPC failed";
00498 struct binrpc_handle rpc_handle;
00499 struct binrpc_response_handle resp_handle;
00500 int i;
00501
00502 str *fn;
00503 struct mi_node *node;
00504 char *command = NULL;
00505 int param_count = 0;
00506 char **parameters = NULL;
00507 struct mi_root* result;
00508
00509 int resp_type;
00510 int resp_code;
00511 char *resp;
00512
00513
00514
00515
00516 static unsigned char *response = NULL;
00517 static int resp_len = 0;
00518
00519 if (binrpc_open_connection_url(&rpc_handle, rpc_url) != 0)
00520 {
00521 LM_ERR( "Open connect to %s failed\n", rpc_url);
00522 result = init_mi_tree( 500, (char *)CONNECT_FAILED, strlen(CONNECT_FAILED) );
00523 goto end;
00524 }
00525
00526 node = cmd_tree->node.kids;
00527
00528 if (node==NULL || node->value.s == NULL)
00529 return( init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN ));
00530
00531 fn = &node->value;
00532
00533
00534 command = pkg_malloc(fn->len+1);
00535 memcpy(command, fn->s, fn->len);
00536 command[fn->len] = '\0';
00537
00538
00539 node = node->next;
00540 while (node) {
00541 if (node->value.s) {
00542 param_count++;
00543 }
00544 node = node->next;
00545 }
00546 if (param_count > 0)
00547 {
00548
00549 parameters = pkg_malloc(param_count * sizeof(char *));
00550
00551 node = cmd_tree->node.kids;
00552 node = node->next;
00553 param_count = 0;
00554 while (node) {
00555 if (node->value.s) {
00556 parameters[param_count] = pkg_malloc(node->value.len + 1);
00557 memcpy(parameters[param_count], node->value.s, node->value.len);
00558 parameters[param_count][node->value.len] = '\0';
00559 param_count++;
00560 }
00561 node = node->next;
00562 }
00563 }
00564 if (binrpc_send_command(&rpc_handle, command, parameters, param_count, &resp_handle))
00565 {
00566 result = init_mi_tree( 500, (char *)FAILED, strlen(FAILED) );
00567 goto end;
00568 }
00569
00570 resp_type = binrpc_get_response_type(&resp_handle);
00571
00572
00573 if (resp_len > 0)
00574 response[0]='\0';
00575
00576 switch (resp_type)
00577 {
00578 case 0:
00579
00580 binrpc_response_to_text(&resp_handle, &response, &resp_len, '\n');
00581 if (strlen((char*)response) > 0)
00582 result = init_mi_tree( 200, (char*)response, strlen((char*)response) );
00583 else
00584
00585 result = init_mi_tree( 200, MI_OK_S, MI_OK_LEN );
00586 break;
00587
00588 case 1:
00589
00590 binrpc_parse_error_response(&resp_handle, &resp_code, &resp);
00591 if (resp_len < strlen(resp) + 1)
00592 {
00593 if (resp_len==0)
00594 response = malloc(strlen(resp) + 1);
00595 else
00596 response = realloc(response, strlen(resp) + 1);
00597 }
00598 memcpy(response, resp, strlen(resp));
00599 response[strlen(resp)]='\0';
00600 if (strlen((char*)response) > 0)
00601 result = init_mi_tree( resp_code, (char*)response, strlen((char*)response) );
00602 else
00603
00604 result = init_mi_tree( resp_code, (char *)FAILED, strlen(FAILED) );
00605 break;
00606
00607 default:
00608 result = init_mi_tree( 500, (char *)FAILED, strlen(FAILED) );
00609 goto end;
00610 }
00611
00612 end:
00613 if (param_count > 0)
00614 {
00615 for (i=0; i<param_count; i++)
00616 {
00617 pkg_free(parameters[i]);
00618 }
00619 pkg_free(parameters);
00620 }
00621 if (command != NULL)
00622 {
00623 pkg_free(command);
00624 command = NULL;
00625 }
00626 binrpc_close_connection(&rpc_handle);
00627 binrpc_release_response(&resp_handle);
00628 return( result );
00629 }