Browse Source

lib/binrpc, modules/mi_rpc: Added MI command to run RPC commands

- Useful for things like running RPC commands from the Siremis MI command page
- Feature added by Andrew Miller @ Crocodile RCS
pd 14 years ago
parent
commit
566347e893

+ 3 - 3
lib/binrpc/binrpc_api.c

@@ -44,9 +44,9 @@
 #include <time.h> /* time */
 /* #include <stropts.h>  - is this really needed? --andrei */
 
-#include "../../modules_s/ctl/ctl_defaults.h" /* default socket & port */
-#include "../../modules_s/ctl/init_socks.h"
-#include "../../modules_s/ctl/binrpc.c" /* ugly hack */
+#include "../../modules/ctl/ctl_defaults.h" /* default socket & port */
+#include "../../modules/ctl/init_socks.h"
+#include "../../modules/ctl/binrpc.c" /* ugly hack */
 
 #include "binrpc_api.h"
 

+ 1 - 1
lib/binrpc/binrpc_api.h

@@ -34,7 +34,7 @@
 #ifndef BINRPC_API_H_
 #define BINRPC_API_H_
 
-#include "../../modules_s/ctl/binrpc.h"
+#include "../../modules/ctl/binrpc.h"
 
 struct binrpc_handle {
 	int socket;

+ 1 - 0
modules/mi_rpc/Makefile

@@ -14,5 +14,6 @@ DEFS+=-DSER_MOD_INTERFACE
 
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+SER_LIBS+=$(SERLIBPATH)/binrpc/binrpc
 
 include ../../Makefile.modules

+ 47 - 5
modules/mi_rpc/README

@@ -25,11 +25,22 @@ Daniel-Constantin Mierla
               2.2. External Libraries or Applications
 
         3. Parameters
+
+              3.1. rpc_url (string)
+
         4. Functions
         5. Exported RPC commands
 
               5.1. mi mi_dg mi_fifo mi_xmlrpc
 
+        6. MI Commands
+
+              6.1. rpc
+
+   List of Examples
+
+   1.1. Set rpc_url parameter
+
 Chapter 1. Admin Guide
 
    Table of Contents
@@ -41,17 +52,22 @@ Chapter 1. Admin Guide
         2.2. External Libraries or Applications
 
    3. Parameters
+
+        3.1. rpc_url (string)
+
    4. Functions
    5. Exported RPC commands
 
         5.1. mi mi_dg mi_fifo mi_xmlrpc
 
-1. Overview
+   6. MI Commands
 
-   The module exports a RPC command to execute MI commands.
+        6.1. rpc
+
+1. Overview
 
-   The other way around not implemented (MI command to execute RPC) -- to
-   be investigated if worth the effort.
+   The module exports a RPC command to execute MI commands and an MI
+   command to run RPC commands.
 
 2. Dependencies
 
@@ -71,7 +87,22 @@ Chapter 1. Admin Guide
 
 3. Parameters
 
-   none
+   3.1. rpc_url (string)
+
+3.1. rpc_url (string)
+
+   Note: this parameter is used for MI to RPC connections.
+
+   This parameters specifies the connection to use for running RPC
+   commands from the mangement interface.
+
+   This parameter is required if you need to run RPC commands from the MI.
+   It must match a URL to which the RPC is bound.
+
+   Example 1.1. Set rpc_url parameter
+...
+modparam("mi_rpc","rpc_url","tcp:localhost:2046")
+...
 
 4. Functions
 
@@ -109,3 +140,14 @@ sercmd> mi uptime
 Now:: Thu Sep 24 18:17:15 2009
 Up since:: Thu Sep 24 17:35:45 2009
 Up time:: 2490 [sec]
+
+6. MI Commands
+
+   6.1. rpc
+
+6.1. rpc
+
+   This MI commands runs a RPC command.
+
+   It must be passed the name of the RPC command, and any parameters that
+   the RPC command requires.

+ 33 - 6
modules/mi_rpc/doc/mi_rpc_admin.xml

@@ -16,11 +16,8 @@
 	<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.
+		The module exports a RPC command to execute MI commands and
+        an MI command to run RPC commands.
 	</para>
 
 	</section>
@@ -57,7 +54,24 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<para>none</para>
+	<section>
+			<title><varname>rpc_url</varname> (string)</title>
+			<para>Note: this parameter is used for MI to RPC connections.</para>
+			<para>
+				This parameters specifies the connection to use for running RPC commands from the mangement interface.
+			</para>
+			<para>
+				This parameter is required if you need to run RPC commands from the MI. It must match a URL to which the RPC is bound.
+			</para>
+			<example>
+				<title>Set <varname>rpc_url</varname> parameter</title>
+				<programlisting>
+...
+modparam("mi_rpc","rpc_url","tcp:localhost:2046")
+...
+				</programlisting>
+			</example>
+		</section>
 	</section>
 	<section>
 	<title>Functions</title>
@@ -121,6 +135,19 @@ Up time:: 2490 [sec]
 		</programlisting>
     </section>
     </section>
+    
+    <section>
+	    <title><acronym>MI</acronym> Commands</title>
+        <section>
+            <title><function moreinfo="none">rpc</function></title>
+            <para>
+            This MI commands runs a RPC command.
+            </para>
+            <para>
+            It must be passed the name of the RPC command, and any parameters that the RPC command requires.
+            </para>
+        </section>
+    </section>
 
 </chapter>
 

+ 167 - 3
modules/mi_rpc/mi_rpc_mod.c

@@ -27,19 +27,25 @@
 
 #include "../../lib/kmi/mi.h"
 #include "../../rpc.h"
+#include "../../lib/binrpc/binrpc_api.h"
 
 MODULE_VERSION
 
 static int child_init(int rank);
+static int mod_init(void);
 
 static str mi_rpc_indent = { "\t", 1 };
+static char *rpc_url = "";
 
 static const char* rpc_mi_exec_doc[2] = {
 	"Execute MI command",
 	0
 };
 
-
+static param_export_t parameters[] = {
+    {"rpc_url",            STR_PARAM, &rpc_url},
+    {0, 0, 0}
+};
 
 enum mi_rpc_print_mode {
 	MI_PRETTY_PRINT,
@@ -67,14 +73,32 @@ struct module_exports exports = {
 	"mi_rpc",
 	0,           /* Exported functions */
 	mr_rpc,      /* RPC methods */
-	0,           /* Export parameters */
-	0,           /* Module initialization function */
+	parameters,  /* Export parameters */
+	mod_init,    /* Module initialization function */
 	0,           /* Response function */
 	0,           /* Destroy function */
 	0,           /* OnCancel function */
 	child_init   /* Child initialization function */
 };
 
+static struct mi_root* mi_run_rpc(struct mi_root* cmd_tree, void* param);
+
+static mi_export_t mi_cmds[] = 
+{
+  { "rpc", mi_run_rpc, 0, 0, 0,},
+  { 0, 0, 0, 0, 0 }
+};
+
+
+static int mod_init(void)
+{
+  if(register_mi_mod(exports.name, mi_cmds)!=0)
+  {
+    LM_ERR("Failed to register MI commands\n");
+    return(-1);
+  }
+  return 0;
+}
 
 static int child_init(int rank)
 {
@@ -465,3 +489,143 @@ static void rpc_mi_xmlrpc_exec(rpc_t* rpc, void* c)
 {
 	rpc_mi_exec(rpc, c, MI_XMLRPC_PRINT);
 }
+
+
+static struct mi_root* mi_run_rpc(struct mi_root* cmd_tree, void* param)
+{
+	const char* FAILED = "Failed";
+	const char* CONNECT_FAILED = "Connection to RPC failed";
+	struct binrpc_handle rpc_handle;
+	struct binrpc_response_handle resp_handle;
+	int i;
+	
+	str *fn;
+	struct mi_node *node;
+	int len;
+	char *command = NULL;
+	int param_count = 0;
+	char **parameters = NULL;
+	struct mi_root* result;
+	
+	int resp_type;
+	int resp_code;
+	char *resp;
+
+	/* response will be malloced by binrpc_response_to_text. 
+	   We do not free it. It must remain after this call.
+	   It will be reused by subsequent calls */
+	static char *response = NULL;
+	static int resp_len = 0;
+	
+	if (binrpc_open_connection_url(&rpc_handle, rpc_url) != 0) 
+	{
+		LM_ERR( "Open connect to %s failed\n", rpc_url);
+		result = init_mi_tree( 500, (char *)CONNECT_FAILED, strlen(CONNECT_FAILED) );
+		goto end;
+	}
+
+	node = cmd_tree->node.kids;
+
+	if (node==NULL || node->value.s == NULL)
+		return( init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN ));
+
+	fn = &node->value;
+	len = fn->len +1;
+	
+	/* find_rpc_exports needs 0 terminated strings */
+	command = pkg_malloc(fn->len+1);
+    memcpy(command, fn->s, fn->len);
+	command[fn->len] = '\0';
+	
+	/* Count the parameters. */
+	node = node->next;
+	while (node) {
+		if (node->value.s) {
+			param_count++;
+		}
+		node = node->next;
+	}
+	if (param_count > 0)
+	{
+		/* Copy them into an array of NULL terminated strings. */
+		parameters = pkg_malloc(param_count * sizeof(char *));
+
+		node = cmd_tree->node.kids;
+		node = node->next;
+		param_count = 0;
+		while (node) {
+			if (node->value.s) {
+				parameters[param_count] = pkg_malloc(node->value.len + 1);
+				memcpy(parameters[param_count], node->value.s, node->value.len);
+				parameters[param_count][node->value.len] = '\0';
+				param_count++;
+			}
+			node = node->next;
+		}
+	}
+	if (binrpc_send_command(&rpc_handle, command, parameters, param_count, &resp_handle))
+	{
+		result = init_mi_tree( 500, (char *)FAILED, strlen(FAILED) );
+		goto end;
+	}
+	
+	resp_type = binrpc_get_response_type(&resp_handle);
+	
+	/* If we already have a buffer make it NULL terminated to discard any previous content */
+	if (resp_len > 0)
+		response[0]='\0';
+
+	switch (resp_type)
+	{
+		case 0:
+			/* Success */
+			binrpc_response_to_text(&resp_handle, (unsigned char **)&response, &resp_len, '\n');
+			if (strlen(response) > 0)
+				result = init_mi_tree( 200, response, strlen(response) );
+			else
+				/* Some functions don't give a text answer; use a default */
+				result = init_mi_tree( 200, MI_OK_S, MI_OK_LEN );
+			break;
+			
+		case 1:
+			/* Valid failure */
+			binrpc_parse_error_response(&resp_handle, &resp_code, &resp);
+			if (resp_len < strlen(resp) + 1)
+			{ 
+				if (resp_len==0)
+					response = malloc(strlen(resp) + 1);
+				else
+					response = realloc(response, strlen(resp) + 1);
+			}
+			memcpy(response, resp, strlen(resp));
+			response[strlen(resp)]='\0';
+			if (strlen(response) > 0)
+				result = init_mi_tree( resp_code, response, strlen(response) );
+			else
+				/* Some functions don't give a text answer; use a default */
+				result = init_mi_tree( resp_code, (char *)FAILED, strlen(FAILED) );
+			break;
+			
+		default:
+			result = init_mi_tree( 500, (char *)FAILED, strlen(FAILED) );
+			goto end;
+	}
+
+end:
+	if (param_count > 0)
+	{
+		for (i=0; i<param_count; i++) 
+		{
+			pkg_free(parameters[i]);
+		}
+		pkg_free(parameters);
+	}
+	if (command != NULL)
+	{
+		pkg_free(command);
+		command = NULL;
+	}
+	binrpc_close_connection(&rpc_handle);
+	binrpc_release_response(&resp_handle);
+	return( result );
+}