struct mi_root *mi_help(struct mi_root *root, void *param) { struct mi_root *rpl_tree = 0; struct mi_node *node; struct mi_node *rpl; struct mi_cmd *cmd; if (!root) { LM_ERR("invalid MI command\n"); return 0; } node = root->node.kids; if (!node || !node->value.len || !node->value.s) { rpl_tree = init_mi_tree(200, MI_SSTR(MI_OK)); if (!rpl_tree) { LM_ERR("cannot init mi tree\n"); return 0; } rpl = &rpl_tree->node; if (!add_mi_node_child(rpl, 0, "Usage", 5, MI_SSTR(MI_HELP_STR))) { LM_ERR("cannot add new child\n"); goto error; } } else { /* search the command */ cmd = lookup_mi_cmd(node->value.s, node->value.len); if (!cmd) return init_mi_tree(404, MI_SSTR(MI_UNKNOWN_CMD)); rpl_tree = init_mi_tree(200, MI_SSTR(MI_OK)); if (!rpl_tree) { LM_ERR("cannot init mi tree\n"); return 0; } rpl = &rpl_tree->node; if (!addf_mi_node_child(rpl, 0, "Help", 4, "%s", cmd->help.s ? cmd->help.s : MI_NO_HELP)) { LM_ERR("cannot add new child\n"); goto error; } if (cmd->module.len && cmd->module.s && !add_mi_node_child(rpl, 0, "Exported by", 11, cmd->module.s, cmd->module.len)) { LM_ERR("cannot add new child\n"); goto error; } } return rpl_tree; error: if (rpl_tree) free_mi_tree(rpl_tree); return 0; }
static struct mi_root* cluster_bcast_mi(struct mi_root *cmd, void *param) { struct mi_node *node, *cmd_params_n; struct mi_cmd *f; unsigned int cluster_id; int rc; str cl_cmd_name; str cl_cmd_params[MI_CMD_MAX_NR_PARAMS]; int no_params = 0; node = cmd->node.kids; if (node == NULL || node->next == NULL || node->next->next == NULL) return init_mi_tree(400, MI_SSTR(MI_MISSING_PARM)); rc = str2int(&node->value, &cluster_id); if (rc < 0 || cluster_id < 1) return init_mi_tree(400, MI_SSTR(MI_BAD_PARM)); cl_cmd_name = node->next->value; f = lookup_mi_cmd(cl_cmd_name.s, cl_cmd_name.len); if (!f) return init_mi_tree(400, MI_SSTR("MI command to be run not found")); cmd_params_n = node->next->next; for (; cmd_params_n; cmd_params_n = cmd_params_n->next, no_params++) cl_cmd_params[no_params] = cmd_params_n->value; /* send MI cmd in cluster */ rc = send_mi_cmd(cluster_id, 0, cl_cmd_name, cl_cmd_params, no_params); switch (rc) { case CLUSTERER_SEND_SUCCES: LM_DBG("MI command <%.*s> sent\n", cl_cmd_name.len, cl_cmd_name.s); break; case CLUSTERER_CURR_DISABLED: LM_INFO("Local node disabled, MI command <%.*s> not sent\n", cl_cmd_name.len, cl_cmd_name.s); break; case CLUSTERER_DEST_DOWN: LM_ERR("All nodes down, MI command <%.*s> not sent\n", cl_cmd_name.len, cl_cmd_name.s); break; case CLUSTERER_SEND_ERR: LM_ERR("Error sending MI command <%.*s>+\n", cl_cmd_name.len, cl_cmd_name.s); break; } /* run MI cmd locally */ return run_mi_cmd_local(f, cl_cmd_params, no_params, cmd->async_hdl); }
/*function that verifyes that the function from the datagram's first * line is correct and exists*/ static int identify_command(datagram_stream * dtgram, struct mi_cmd * *f) { char *command,*p, *start; /* default offset for the command: 0 */ p= dtgram->start; start = p; if (!p){ LM_ERR("null pointer \n"); return -1; } /*if no command*/ if ( dtgram->len ==0 ){ LM_DBG("command empty case1 \n"); goto error; } if (*p != MI_CMD_SEPARATOR){ LM_ERR("command must begin with: %c \n", MI_CMD_SEPARATOR); goto error; } command = p+1; LM_DBG("the command starts here: %s\n", command); p=strchr(command, MI_CMD_SEPARATOR ); if (!p ){ LM_ERR("empty command \n"); goto error; } if(*(p+1)!='\n'){ LM_ERR("the request's first line is invalid :no newline after " "the second %c\n",MI_CMD_SEPARATOR); goto error; } /* make command zero-terminated */ *p=0; LM_DBG("the command is %s\n",command); /*search for the appropiate command*/ *f=lookup_mi_cmd( command, p-command); if(!*f) goto error; /*the current offset has changed*/ LM_DBG("dtgram->len is %i\n", dtgram->len); dtgram->current = p+2 ; dtgram->len -=p+2 - dtgram->start; LM_DBG("dtgram->len is %i\n",dtgram->len); return 0; error: return -1; }
struct mi_root *run_rcv_mi_cmd(str *cmd_name, str *cmd_params, int nr_params) { struct mi_cmd *f; struct mi_root *cmd_root = NULL, *cmd_rpl; int i; f = lookup_mi_cmd(cmd_name->s, cmd_name->len); if (!f) { LM_ERR("MI command to be run not found\n"); return NULL; } if (f->flags & MI_NO_INPUT_FLAG && nr_params) { LM_ERR("MI command should not have parameters\n"); return NULL; } if (!(f->flags & MI_NO_INPUT_FLAG)) { cmd_root = init_mi_tree(0,0,0); if (!cmd_root) { LM_ERR("the MI tree for the command to be run cannot be initialized!\n"); return NULL; } } for (i = 0; i < nr_params; i++) if (!add_mi_node_child(&cmd_root->node, 0, 0, 0, cmd_params[i].s, cmd_params[i].len)) { free_mi_tree(cmd_root); LM_ERR("cannot add child node to the tree of the MI command to be run\n"); return NULL; } if ((cmd_rpl = run_mi_cmd(f, cmd_root, 0, 0)) == NULL) { if (cmd_root) free_mi_tree(cmd_root); return NULL; } if (cmd_root) free_mi_tree(cmd_root); return cmd_rpl; }
void mi_fifo_server(FILE *fifo_stream) { struct mi_root *mi_cmd; struct mi_root *mi_rpl; struct mi_handler *hdl; int line_len; char *file_sep, *command, *file; struct mi_cmd *f; FILE *reply_stream; while(1) { reply_stream = NULL; /* commands must look this way ':<command>:[filename]' */ if (mi_read_line(mi_buf,MAX_MI_FIFO_BUFFER,fifo_stream, &line_len)) { LM_ERR("failed to read command\n"); continue; } /* trim from right */ while(line_len) { if(mi_buf[line_len-1]=='\n' || mi_buf[line_len-1]=='\r' || mi_buf[line_len-1]==' ' || mi_buf[line_len-1]=='\t' ) { line_len--; mi_buf[line_len]=0; } else break; } if (line_len==0) { LM_DBG("command empty\n"); continue; } if (line_len<3) { LM_ERR("command must have at least 3 chars\n"); continue; } if (*mi_buf!=MI_CMD_SEPARATOR) { LM_ERR("command must begin with %c: %.*s\n", MI_CMD_SEPARATOR, line_len, mi_buf ); goto consume1; } command = mi_buf+1; file_sep=strchr(command, MI_CMD_SEPARATOR ); if (file_sep==NULL) { LM_ERR("file separator missing\n"); goto consume1; } if (file_sep==command) { LM_ERR("empty command\n"); goto consume1; } if (*(file_sep+1)==0) { file = NULL; } else { file = file_sep+1; file = get_reply_filename(file, mi_buf+line_len-file); if (file==NULL) { LM_ERR("trimming filename\n"); goto consume1; } } /* make command zero-terminated */ *file_sep=0; f=lookup_mi_cmd( command, strlen(command) ); if (f==0) { LM_ERR("command %s is not available\n", command); mi_open_reply( file, reply_stream, consume1); mi_fifo_reply( reply_stream, "500 command '%s' not available\n", command); goto consume2; } /* if asyncron cmd, build the async handler */ if (f->flags&MI_ASYNC_RPL_FLAG) { hdl = build_async_handler( file, strlen(file) ); if (hdl==0) { LM_ERR("failed to build async handler\n"); mi_open_reply( file, reply_stream, consume1); mi_fifo_reply( reply_stream, "500 Internal server error\n"); goto consume2; } } else { hdl = 0; mi_open_reply( file, reply_stream, consume1); } if (f->flags&MI_NO_INPUT_FLAG) { mi_cmd = 0; mi_do_consume(); } else { mi_cmd = mi_parse_tree(fifo_stream); if (mi_cmd==NULL) { LM_ERR("error parsing MI tree\n"); if (!reply_stream) mi_open_reply( file, reply_stream, consume3); mi_fifo_reply( reply_stream, "400 parse error in " "command '%s'\n", command); goto consume3; } mi_cmd->async_hdl = hdl; } LM_DBG("done parsing the mi tree\n"); if ( (mi_rpl=run_mi_cmd(f, mi_cmd, (mi_flush_f *)mi_flush_tree, reply_stream))==0 ) { if (!reply_stream) mi_open_reply( file, reply_stream, failure); mi_fifo_reply(reply_stream, "500 command '%s' failed\n", command); LM_ERR("command (%s) processing failed\n", command ); } else if (mi_rpl!=MI_ROOT_ASYNC_RPL) { if (!reply_stream) mi_open_reply( file, reply_stream, failure); mi_write_tree( reply_stream, mi_rpl); free_mi_tree( mi_rpl ); } else { if (mi_cmd) free_mi_tree( mi_cmd ); continue; } free_async_handler(hdl); /* close reply fifo */ fclose(reply_stream); /* destroy request tree */ if (mi_cmd) free_mi_tree( mi_cmd ); continue; failure: free_async_handler(hdl); /* destroy request tree */ if (mi_cmd) free_mi_tree( mi_cmd ); /* destroy the reply tree */ if (mi_rpl) free_mi_tree(mi_rpl); continue; consume3: free_async_handler(hdl); if (reply_stream) consume2: fclose(reply_stream); consume1: mi_do_consume(); } }
void mi_json_answer_to_connection (void *cls, void *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls, str *buffer, str *page) { str command = {NULL, 0}; str params = {NULL, 0}; struct mi_cmd *f = NULL; struct mi_root *tree = NULL; struct mi_handler *async_hdl; LM_DBG("START *** cls=%p, connection=%p, url=%s, method=%s, " "versio=%s, upload_data[%d]=%p, *con_cls=%p\n", cls, connection, url, method, version, (int)*upload_data_size, upload_data, *con_cls); if (strncmp(method, "GET", 3)==0) { if(url && url[0] == '/' && url[1] != '\0') { command.s = (char*)url+1; command.len = strlen(command.s); } httpd_api.lookup_arg(connection, "params", *con_cls, ¶ms); if (command.s) { f = lookup_mi_cmd(command.s, command.len); if (f == NULL) { LM_ERR("unable to find mi command [%.*s]\n", command.len, command.s); *page = MI_HTTP_U_NOT_FOUND; } else { tree = mi_json_run_mi_cmd(f, &command,¶ms, page, buffer, &async_hdl); if (tree == NULL) { LM_ERR("no reply\n"); *page = MI_HTTP_U_ERROR; } else if (tree == MI_ROOT_ASYNC_RPL) { LM_DBG("got an async reply\n"); tree = NULL; } else { LM_DBG("building on page [%p:%d]\n", page->s, page->len); if(0!=mi_json_build_page(page, buffer->len, tree)){ LM_ERR("unable to build response\n"); *page = MI_HTTP_U_ERROR; } } } } else { page->s = buffer->s; LM_ERR("unable to build response for empty request\n"); *page = MI_HTTP_U_ERROR; } if (tree) { free_mi_tree(tree); tree = NULL; } } else { LM_ERR("unexpected method [%s]\n", method); *page = MI_HTTP_U_METHOD; } return; }
static mi_response_t *cl_run_mi_cmd(str *cmd_name, mi_item_t *item_params_arr, str *str_params_arr, int no_params) { struct mi_cmd *cmd = NULL; mi_response_t *resp = NULL; mi_request_t req_item; mi_item_t *param_item; int i; str val; memset(&req_item, 0, sizeof req_item); req_item.req_obj = cJSON_CreateObject(); if (!req_item.req_obj) { LM_ERR("Failed to build temporary json request\n"); return NULL; } cmd = lookup_mi_cmd(cmd_name->s, cmd_name->len); if (!cmd) { resp = init_mi_error(400, MI_SSTR("Command to be run not found")); goto out; } if (cmd->flags & MI_ASYNC_RPL_FLAG) { resp = init_mi_error(400, MI_SSTR("Async commands not supported")); goto out; } if (cmd->flags & MI_NAMED_PARAMS_ONLY) { resp = init_mi_error(400, MI_SSTR("Commands requiring named params not supported")); goto out; } if (no_params) { req_item.params = cJSON_CreateArray(); if (!req_item.params) { LM_ERR("Failed to add 'params' to temporary json request\n"); goto out; } cJSON_AddItemToObject(req_item.req_obj, JSONRPC_PARAMS_S, req_item.params); } for (i = 0; i < no_params; i++) { if (item_params_arr) { if (get_mi_arr_param_string(item_params_arr, i, &val.s, &val.len) < 0) { resp = init_mi_param_error(); goto out; } } else { val.s = str_params_arr[i].s; val.len = str_params_arr[i].len; } param_item = cJSON_CreateStr(val.s, val.len); if (!param_item) { LM_ERR("Failed to create string item in temporary json request\n"); goto out; } cJSON_AddItemToArray(req_item.params, param_item); } resp = handle_mi_request(&req_item, cmd, NULL); LM_DBG("got mi response = [%p]\n", resp); out: cJSON_Delete(req_item.req_obj); return resp; }
static void rpc_mi_exec(rpc_t *rpc, void *ctx, enum mi_rpc_print_mode mode) { str cmd; struct mi_cmd *mic; struct mi_root *mi_req; struct mi_root *mi_rpl; struct mi_handler* mi_async_h; struct mi_rpc_handler_param* mi_handler_param; if (rpc->scan(ctx, "S", &cmd) < 1) { LM_ERR("command parameter not found\n"); rpc->fault(ctx, 500, "command parameter missing"); return; } mi_async_h=0; mi_req = 0; mi_rpl=0; mic = lookup_mi_cmd(cmd.s, cmd.len); if(mic==0) { LM_ERR("mi command %.*s is not available\n", cmd.len, cmd.s); rpc->fault(ctx, 500, "command not available"); return; } if (mic->flags&MI_ASYNC_RPL_FLAG) { if (rpc->capabilities==0 || !(rpc->capabilities(ctx) & RPC_DELAYED_REPLY)) { rpc->fault(ctx, 500, "this rpc transport does not support async mode"); return; } } if(!(mic->flags&MI_NO_INPUT_FLAG)) { mi_req = mi_rpc_read_params(rpc, ctx); if(mi_req==NULL) { LM_ERR("cannot parse parameters\n"); rpc->fault(ctx, 500, "cannot parse parameters"); goto error; } if (mic->flags&MI_ASYNC_RPL_FLAG) { /* build mi async handler */ mi_handler_param=shm_malloc(sizeof(*mi_handler_param)); if (mi_handler_param==0) { rpc->fault(ctx, 500, "out of memory"); return; } mi_async_h=shm_malloc(sizeof(*mi_async_h)); if (mi_async_h==0) { shm_free(mi_handler_param); mi_handler_param=0; rpc->fault(ctx, 500, "out of memory"); return; } memset(mi_async_h, 0, sizeof(*mi_async_h)); mi_async_h->handler_f=mi_rpc_async_close; mi_handler_param->mode=mode; mi_handler_param->dctx=rpc->delayed_ctx_new(ctx); if (mi_handler_param->dctx==0) { rpc->fault(ctx, 500, "internal error: async ctx" " creation failed"); goto error; } /* switch context, since replies are not allowed anymore on the original one */ rpc=&mi_handler_param->dctx->rpc; ctx=mi_handler_param->dctx->reply_ctx; mi_async_h->param=mi_handler_param; } mi_req->async_hdl=mi_async_h; } mi_rpl=run_mi_cmd(mic, mi_req); if(mi_rpl == 0) { rpc->fault(ctx, 500, "execution failed"); goto error; } if (mi_rpl!=MI_ROOT_ASYNC_RPL) { mi_rpc_print_tree(rpc, ctx, mi_rpl, mode); goto end; } else if (mi_async_h==0) { /* async reply, but command not listed as async */ rpc->fault(ctx, 500, "bad mi command: unexpected async reply"); goto error; } mi_async_h=0; /* don't delete it */ end: error: if (mi_req) free_mi_tree(mi_req); if (mi_rpl && mi_rpl!=MI_ROOT_ASYNC_RPL) free_mi_tree(mi_rpl); if (mi_async_h) { if (mi_async_h->param) { if (((struct mi_rpc_handler_param*)mi_async_h->param)->dctx) rpc->delayed_ctx_close(((struct mi_rpc_handler_param*) mi_async_h->param)->dctx); shm_free(mi_async_h->param); } shm_free(mi_async_h); } return; }
xmlrpc_value* default_method (xmlrpc_env* env, const char* host, const char* methodName, xmlrpc_value* paramArray, void* serverInfo) #endif { xmlrpc_value* ret = NULL; struct mi_root* mi_cmd = NULL; struct mi_root* mi_rpl = NULL; struct mi_handler *hdl = NULL; struct mi_cmd* f; char* response = 0; int is_shm = 0; LM_DBG("starting up.....\n"); f = lookup_mi_cmd((char*)methodName, strlen(methodName)); if ( f == 0 ) { LM_ERR("command %s is not available!\n", methodName); xmlrpc_env_set_fault_formatted(env, XMLRPC_NO_SUCH_METHOD_ERROR, "Requested command (%s) is not available!", methodName); goto error; } LM_DBG("done looking the mi command.\n"); /* if asyncron cmd, build the async handler */ if (f->flags&MI_ASYNC_RPL_FLAG) { hdl = build_async_handler( ); if (hdl==0) { LM_ERR("failed to build async handler\n"); if ( !env->fault_occurred ) xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR, "Internal server error while processing request"); goto error; } } else { hdl = NULL; } if (f->flags&MI_NO_INPUT_FLAG) { mi_cmd = 0; } else { mi_cmd = xr_parse_tree(env, paramArray); if ( mi_cmd == NULL ){ LM_ERR("failed to parse MI tree\n"); if ( !env->fault_occurred ) xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR, "The xmlrpc request could not be parsed into a MI tree!"); goto error; } mi_cmd->async_hdl = hdl; } LM_DBG("done parsing the mi tree.\n"); if ( ( mi_rpl = run_mi_cmd(f, mi_cmd) ) == 0 ){ LM_ERR("command (%s) processing failed.\n", methodName); xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, "Command (%s) processing failed.\n", methodName); goto error; } else if (mi_rpl==MI_ROOT_ASYNC_RPL) { mi_rpl = wait_async_reply(hdl); hdl = 0; if (mi_rpl==0) { xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, "Command (%s) processing failed (async).\n", methodName); goto error; } is_shm = 1; } LM_DBG("done running the mi command.\n"); if ( rpl_opt == 1 ) { if ( xr_build_response_array( env, mi_rpl ) != 0 ){ if ( !env->fault_occurred ) { LM_ERR("failed parsing the xmlrpc response from the mi tree\n"); xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR, "Failed to parse the xmlrpc response from the mi tree."); } goto error; } LM_DBG("done building response array.\n"); ret = xr_response; } else { if ( (response = xr_build_response( env, mi_rpl )) == 0 ){ if ( !env->fault_occurred ) { LM_ERR("failed parsing the xmlrpc response from the mi tree\n"); xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, "Failed to parse the xmlrpc response from the mi tree."); } goto error; } LM_DBG("done building response.\n"); ret = xmlrpc_build_value(env, "s", response); } error: free_async_handler(hdl); if ( mi_cmd ) free_mi_tree( mi_cmd ); if ( mi_rpl ) { is_shm?free_shm_mi_tree(mi_rpl):free_mi_tree(mi_rpl);} return ret; }