浏览代码

mi_rpc: new module - rpc command to execute MI commands

- 'mi' rpc command can be used to execute K MI commands
- example using sercmd:
sercmd> mi uptime
200 OK

+ Now:: Sun Jun 28 12:45:37 2009
+ Up since:: Sun Jun 28 12:24:27 2009
+ Up time:: 1270 [sec]
Daniel-Constantin Mierla 16 年之前
父节点
当前提交
1f03418827

+ 18 - 0
modules/mi_rpc/Makefile

@@ -0,0 +1,18 @@
+# $Id$
+#
+# mi_rpc module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=mi_rpc.so
+LIBS=
+
+DEFS+=-DSER_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+
+include ../../Makefile.modules

+ 84 - 0
modules/mi_rpc/README

@@ -0,0 +1,84 @@
+MI_RPC Module
+
+Daniel-Constantin Mierla
+
+   asipto.com
+   <[email protected]>
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+   Copyright © 2009 http://www.asipto.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1.1. Overview
+        1.2. Dependencies
+
+              1.2.1. Kamailio Modules
+              1.2.2. External Libraries or Applications
+
+        1.3. Exported Parameters
+        1.4. Exported Functions
+        1.5. Exported RPC commands
+
+              1.5.1. mi
+
+Chapter 1. Admin Guide
+
+1.1. Overview
+
+   The module exports a RPC command to execute MI commands.
+
+   The other way around not implemented (MI command to execute RPC) -- to
+   be investigated if worth the effort. Also, execution of asynchronous MI
+   command is not yet supported.
+
+1.2. Dependencies
+
+1.2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * No dependencies on other Kamailio modules.
+
+1.2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * None.
+
+1.3. Exported Parameters
+
+   none
+
+1.4. Exported Functions
+
+   none
+
+1.5. Exported RPC commands
+
+1.5.1.  mi
+
+   Execute a MI command.
+
+   Name: mi
+
+   Parameters:
+
+   _mi_command_ - the MI command to execute (mandatory).
+
+   _parameters_ - the MI command parameters (optional).
+
+   Example using 'sercmd':
+sercmd> mi uptime
+200 OK
+
++ Now:: Sun Jun 28 12:45:37 2009
++ Up since:: Sun Jun 28 12:24:27 2009
++ Up time:: 1270 [sec]

+ 4 - 0
modules/mi_rpc/doc/Makefile

@@ -0,0 +1,4 @@
+docs = mi_rpc.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 43 - 0
modules/mi_rpc/doc/mi_rpc.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>MI_RPC Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<affiliation><orgname>asipto.com</orgname></affiliation>
+		<email>[email protected]</email>
+		<address>
+		<otheraddr>
+		<ulink url="http://www.asipto.com">http://www.asipto.com</ulink>
+		</otheraddr>
+		</address>
+	    </author>
+	    <editor>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2009</year>
+	    <holder>http://www.asipto.com</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="mi_rpc_admin.xml"/>
+    
+    
+</book>

+ 103 - 0
modules/mi_rpc/doc/mi_rpc_admin.xml

@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+		The module exports a RPC command to execute MI commands.
+	</para>
+	<para>
+		The other way around not implemented (MI command to execute RPC)
+		-- to be investigated if worth the effort. Also, execution of 
+		asynchronous MI command is not yet supported.
+	</para>
+
+	</section>
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>No dependencies on other &kamailio; modules</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>None</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+
+	</section>
+	<section>
+	<title>Exported Parameters</title>
+	<para>none</para>
+	</section>
+	<section>
+	<title>Exported Functions</title>
+	<para>none</para>
+	</section>
+	<section>
+	<title>Exported RPC commands</title>
+	<section>
+		<title>
+		<function moreinfo="none">mi</function>
+		</title>
+		<para>
+		Execute a MI command.
+		</para>
+		<para>
+		Name: <emphasis>mi</emphasis>
+		</para>
+		<para>Parameters:</para>
+		<para>
+			<emphasis>_mi_command_</emphasis> - the MI command to execute
+			(mandatory).
+		</para>
+		<para>
+			<emphasis>_parameters_</emphasis> - the MI command parameters
+			(optional).
+		</para>
+ 		<para>
+		Example using 'sercmd':
+		</para>
+		<programlisting  format="linespecific">
+sercmd> mi uptime
+200 OK
+
++ Now:: Sun Jun 28 12:45:37 2009
++ Up since:: Sun Jun 28 12:24:27 2009
++ Up time:: 1270 [sec]
+		</programlisting>
+    </section>
+    </section>
+
+</chapter>
+

+ 228 - 0
modules/mi_rpc/mi_rpc_mod.c

@@ -0,0 +1,228 @@
+/*
+ * $Id$
+ *
+ * mi_rpc module
+ *
+ * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com).
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+
+#include "../../lib/kmi/mi.h"
+#include "../../rpc.h"
+
+MODULE_VERSION
+
+static str mi_rpc_indent = { "\t", 1 };
+
+static const char* rpc_mi_exec_doc[2] = {
+	"Execut MI command",
+	0
+};
+
+static void rpc_mi_exec(rpc_t* rpc, void* c);
+
+rpc_export_t mr_rpc[] = {
+	{"mi",  rpc_mi_exec,  rpc_mi_exec_doc,  0},
+	{0, 0, 0, 0}
+};
+
+struct module_exports exports = {
+	"mi_rpc",
+	0,        /* Exported functions */
+	mr_rpc,   /* RPC methods */
+	0,        /* Export parameters */
+	0,        /* Module initialization function */
+	0,        /* Response function */
+	0,        /* Destroy function */
+	0,        /* OnCancel function */
+	0         /* Child initialization function */
+};
+
+struct mi_root *mi_rpc_read_params(rpc_t *rpc, void *ctx)
+{
+	struct mi_root *root;
+	struct mi_node *node;
+	str name;
+	str value;
+
+	root = init_mi_tree(0,0,0);
+	if (!root) {
+		LM_ERR("the MI tree cannot be initialized!\n");
+		goto error;
+	}
+	node = &root->node;
+
+	while (rpc->scan(ctx, "*S", &value) == 1)
+	{
+		name.s   = 0;
+		name.len = 0;
+		
+		if(value.len>=2 && value.s[0]=='-' && value.s[1]=='-')
+		{
+			/* name */
+			if(value.len>2)
+			{
+				name.s   = value.s + 2;
+				name.len = value.len - 2;
+			}
+
+			/* value */
+			if(rpc->scan(ctx, "*S", &value) != 1)
+			{
+				LM_ERR("value expected\n");
+				goto error;
+			}
+		}
+
+		if(!add_mi_node_child(node, 0, name.s, name.len,
+					value.s, value.len))
+		{
+			LM_ERR("cannot add the child node to the MI tree\n");
+			goto error;
+		}
+	}
+
+	return root;
+
+error:
+	if (root)
+		free_mi_tree(root);
+	return 0;
+}
+
+static int mi_rpc_rprint_node(rpc_t* rpc, void* ctx, struct mi_node *node,
+		int level)
+{
+	struct mi_attr *attr;
+	char indent[32];
+	int i;
+	char *p;
+
+	if(level*mi_rpc_indent.len>=32)
+	{
+		LM_ERR("too many recursive levels for indentation\n");
+		return -1;
+	}
+	p = indent;
+	for(i=0; i<level; i++)
+	{
+		memcpy(p, mi_rpc_indent.s, mi_rpc_indent.len);
+		p += mi_rpc_indent.len;
+	}
+	*p = 0;
+	for( ; node ; node=node->next )
+	{
+		rpc->printf(ctx, "%s+ %.*s:: %.*s",
+				indent,
+				node->name.len, (node->name.s)?node->name.s:"",
+				node->value.len, (node->value.s)?node->value.s:"");
+	
+		for( attr=node->attributes ; attr!=NULL ; attr=attr->next ) {
+			rpc->printf(ctx, "%s%.*s  - %.*s=%.*s",
+					indent, mi_rpc_indent.len, mi_rpc_indent.s,
+					attr->name.len, (attr->name.s)?attr->name.s:"",
+					attr->value.len, (attr->value.s)?attr->value.s:"");
+		}
+
+		if (node->kids) {
+			if (mi_rpc_rprint_node(rpc, ctx, node->kids, level+1)<0)
+				return -1;
+		}
+	}
+	return 0;
+}
+
+static int mi_rpc_print_tree(rpc_t* rpc, void* ctx, struct mi_root *tree)
+{
+	rpc->printf(ctx, "%d %.*s\n", tree->code,
+			tree->reason.len, tree->reason.s);
+
+	if (tree->node.kids)
+	{
+		if (mi_rpc_rprint_node(rpc, ctx, tree->node.kids, 0)<0)
+			return -1;
+	}
+	
+	return 0;
+}
+
+static void rpc_mi_exec(rpc_t *rpc, void *ctx)
+{
+	str cmd;
+	struct mi_cmd *mic;
+	struct mi_root *mi_req;
+	struct mi_root *mi_rpl;
+
+	if (rpc->scan(ctx, "S", &cmd) < 1)
+	{
+		LM_ERR("command parameter not found\n");
+		rpc->fault(ctx, 500, "command parameter missing");
+		return;
+	}
+
+	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)
+	{
+		LM_ERR("async mi cmd support not implemented yet\n");
+		rpc->fault(ctx, 500, "async my cmd not implemented yet");
+		return;
+	}
+
+	mi_req = 0;
+	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");
+			return;
+		}
+	}
+	mi_rpl=run_mi_cmd(mic, mi_req);
+
+	if(mi_rpl == 0)
+	{
+		rpc->fault(ctx, 500, "execution failed");
+		if (mi_req) free_mi_tree(mi_req);
+		return;
+	}
+
+	if (mi_rpl!=MI_ROOT_ASYNC_RPL)
+	{
+		mi_rpc_print_tree(rpc, ctx, mi_rpl);
+		free_mi_tree(mi_rpl);
+		if (mi_req) free_mi_tree(mi_req);
+		return;
+	}
+
+	/* async cmd -- not yet */
+	rpc->fault(ctx, 500, "no async handling yet");
+	if (mi_req) free_mi_tree(mi_req);
+	return;
+}