Daniel-Constantin Mierla writes:
> here is what mi_rpc modules does:
> - it receives a rpc handler form the rpc interface in core
> - reads first parameter and then lookups MI command, if not found then
> returns error, if found:
> - reads all parameters as string and build internal MI tree
ok, after andrei fixed some bug, i got stats working via mi_rpc and
xmlrpc module interface.
all stats except "tm:", which is now implemented using tm.stats command.
res = c.tm.stats()
provides this kind of result:
{'2xx': 0, 'created': 0, '5xx': 0, 'delayed_free': 0, 'current': 0, 'total_local': 0, 'waiting': 0, '6xx': 0, '4xx': 0, '3xx': 0, 'total': 0, 'replied_locally': 0, 'freed': 0}
whereas mi based stat results look like this:
['200 OK\n', '+ :: core:rcv_requests = 3', '+ :: core:rcv_replies = 0', '+ :: core:fwd_requests = 0', '+ :: core:fwd_replies = 0', '+ :: core:drop_requests = 0', '+ :: core:drop_replies = 0', '+ :: core:err_requests = 0', '+ :: core:err_replies = 0', '+ :: core:bad_URIs_rcvd = 0', '+ :: core:unsupported_methods = 3', '+ :: core:bad_msg_hdr = 0']
would it be possible to get the result in same (preferable the former)
format in both cases?
-- juha
Module: sip-router
Branch: master
Commit: 4903fc5f9b5fa2b6047780dc192d6b41fd746d68
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=4903fc5…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Mon Jul 13 19:04:52 2009 +0200
xmlrpc(s): added rpc client examples
Added rpc client examples/test scripts in perl and python. The
python script has 2 versions: one with re-defined transport (that
works properly without expecting the server side to immediately
close the connection after answering) and one using the default
xmlrpclib transport (which requires closing the connection from
the ser xmlrpc route).
---
modules_s/xmlrpc/examples/xmlrpc_test.pl | 67 +++++++++++++++++++++++++++++
modules_s/xmlrpc/examples/xmlrpc_test.py | 51 ++++++++++++++++++++++
modules_s/xmlrpc/examples/xmlrpc_test2.py | 29 ++++++++++++
3 files changed, 147 insertions(+), 0 deletions(-)
diff --git a/modules_s/xmlrpc/examples/xmlrpc_test.pl b/modules_s/xmlrpc/examples/xmlrpc_test.pl
new file mode 100644
index 0000000..dbb32b8
--- /dev/null
+++ b/modules_s/xmlrpc/examples/xmlrpc_test.pl
@@ -0,0 +1,67 @@
+#!/usr/bin/perl
+
+# perl script for sending an xmlrpc command to ser's xmlrpc module,
+# extra verbose output
+# Usage: perl xmlrpc_test.pl command [params...]
+#
+# History:
+# --------
+# 2009-07-13 initial version (andrei)
+#
+#
+
+use strict;
+use warnings;
+
+use XMLRPC::Lite;
+
+ my $rpc=shift @ARGV;
+ my @rpc_params=@ARGV;
+ my $k;
+ my %r;
+ my $i;
+
+ if (!defined $rpc) {
+ die "Usage: $0 rpc_command [args..]";
+ }
+
+# actual rpc call
+
+ my($rpc_call) = XMLRPC::Lite
+ -> proxy("http://127.0.0.1:5060") -> call($rpc, @rpc_params);
+
+ my $res= $rpc_call->result;
+
+# extra verbose result printing (could be skipped)
+
+ if (!defined $res){
+ print "fault{\n";
+ $res=$rpc_call->fault;
+ %r=%{$res};
+ foreach $k (sort keys %r) {
+ print("\t$k: $r{$k}\n");
+ }
+ print "}\n";
+ exit -1;
+ }
+ if (ref($res) eq "HASH"){
+ print("{\n");
+ %r=%{$res};
+ foreach $k (keys %r) {
+ print("\t$k: ", $r{$k}, "\n");
+ }
+ print("}\n");
+ } elsif (ref($res) eq "ARRAY"){
+ print "[\n";
+ for ($i=0; $i<@{$res}; $i++){
+ print "\t${$res}[$i]\n";
+ }
+ print "]\n";
+ }elsif (ref($res) eq "SCALAR"){
+ print "${$res}\n";
+ }elsif (!ref($res)){
+ print "$res\n";
+ }else{
+ print("ERROR: reference to ", ref($res), " not handled\n");
+ }
+
diff --git a/modules_s/xmlrpc/examples/xmlrpc_test.py b/modules_s/xmlrpc/examples/xmlrpc_test.py
new file mode 100644
index 0000000..0bf1591
--- /dev/null
+++ b/modules_s/xmlrpc/examples/xmlrpc_test.py
@@ -0,0 +1,51 @@
+import xmlrpclib, httplib, sys
+
+# Usage: python xmlrpc_test.py command [params...]
+#
+# python script for sending an xmlrpc command to ser's xmlrpc module.
+# Note: it uses a re-defined transport class that does not depend on the
+# server side closing the connection (it can be used to send multiple
+# commands without closing the connections and it will work without any
+# special workarounds in the ser.cfg xmlrpc route).
+#
+# Credits: the transport class comes from ser_ctl, heavily trimmed to a very
+# basic version (the ser_ctl version is much more complex, supports
+# authentication, ssl a.s.o). See
+# http://git.sip-router.org/cgi-bin/gitweb.cgi?p=ser;a=blob;f=ser_ctl/serctl/… for the original (better) version.
+#
+#
+# History:
+# --------
+# 2009-07-13 initial version (andrei)
+#
+
+
+XMLRPC_SERVER = "127.0.0.1"
+XMLRPC_PORT = 5060
+
+class Transport:
+ def __init__(self):
+ self.conn=httplib.HTTPConnection(XMLRPC_SERVER, str(XMLRPC_PORT));
+
+ def _http_request(self, uripath, body, host):
+ self.conn.request("POST", uripath, body, {})
+
+ def request(self, host, uripath, body, verbose=0):
+ self._http_request(uripath, body, host)
+ response=self.conn.getresponse()
+ if response.status != 200:
+ raise xmlrpclib.ProtocolError(host+uripath, response.status,
+ response.reason, response.msg)
+ data=response.read()
+ parser, unmarshaller=xmlrpclib.getparser()
+ parser.feed(data)
+ parser.close()
+ return unmarshaller.close()
+
+if len(sys.argv) < 2:
+ sys.exit("Usage: "+sys.argv[0]+" rpc_command [args...]");
+transport=Transport()
+c=xmlrpclib.ServerProxy("http://" + XMLRPC_SERVER+ ":" + str(XMLRPC_PORT),
+ transport)
+res=getattr(c, sys.argv[1])(*sys.argv[2:])
+print res;
diff --git a/modules_s/xmlrpc/examples/xmlrpc_test2.py b/modules_s/xmlrpc/examples/xmlrpc_test2.py
new file mode 100644
index 0000000..0fdee1e
--- /dev/null
+++ b/modules_s/xmlrpc/examples/xmlrpc_test2.py
@@ -0,0 +1,29 @@
+import xmlrpclib, httplib, sys
+
+# Usage: python xmlrpc_test2.py command [params...]
+#
+# python script for sending an xmlrpc command to ser's xmlrpc module.
+# This script uses python xmlrpclib directly and expects the remote side to
+# immediately close the connection after answering (broken xmlrpclib
+# behaviour).
+# There are 2 way to make it work with ser xmlrpc module: define a
+# better transport class (that's what the xmlrpc_test.py script is doing) or
+# change ser xmlrpc route so that it will close the connection after each
+# processes xmlrpc request (e.g. add a drop -1 at the end).
+#
+# See also: xmlrpc_test.py (better version, using a redefined transport class).
+#
+# History:
+# --------
+# 2009-07-13 initial version (andrei)
+#
+
+XMLRPC_SERVER = "127.0.0.1"
+XMLRPC_PORT = 5060
+
+
+if len(sys.argv) < 2:
+ sys.exit("Usage: "+sys.argv[0]+" rpc_command [args...]");
+c=xmlrpclib.ServerProxy("http://" + XMLRPC_SERVER+ ":" + str(XMLRPC_PORT))
+res=getattr(c, sys.argv[1])(*sys.argv[2:])
+print res;
Daniel-Constantin Mierla writes:
> several days ago, a new module named mi_rpc was introduced to source
> tree. The goal is to be able to execute MI commands using RPC interface
> from sip router core.
>
> Back to mi_rpc, one issue that needs to be sorted out is the output
> format. Right now doing a pretty-format printing which is not suitable
> for xmlrpc.
>
> Feedback is very much appreciated, thanks,
i tried to get core stats out using xmlrcp. using serctl, i can do it
like this:
srctl mi get_statistics core:200 OK
+ :: core:rcv_requests = 10
+ :: core:rcv_replies = 0
+ :: core:fwd_requests = 0
+ :: core:fwd_replies = 0
+ :: core:drop_requests = 0
+ :: core:drop_replies = 0
+ :: core:err_requests = 0
+ :: core:err_replies = 0
+ :: core:bad_URIs_rcvd = 0
+ :: core:unsupported_methods = 10
+ :: core:bad_msg_hdr = 0
using xmlrpc interface, i tried by giving command called "mi" with
argument list "get_statistics" and "core":, but it didn't work:
c.mi(['get_statistics', 'core:'])
...
xmlrpclib.Fault: <Fault 500: 'command parameter missing'>
how is the actual command and and its arguments supplied?
-- juha
Module: sip-router
Branch: master
Commit: e792b7614aaa57ddf4482a23e21c959dd2f45f98
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=e792b76…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Mon Jul 13 18:00:40 2009 +0200
xmlrpc(s): fix '*' rpc_scan handling
The '*' modifier (marking the next parameters as optional) was not
properly handled (the current input parameter was "eaten").
Reported-by: Juha Heinanen jh at tutpro com
---
modules_s/xmlrpc/xmlrpc.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/modules_s/xmlrpc/xmlrpc.c b/modules_s/xmlrpc/xmlrpc.c
index 56b2151..0de5145 100644
--- a/modules_s/xmlrpc/xmlrpc.c
+++ b/modules_s/xmlrpc/xmlrpc.c
@@ -1220,9 +1220,9 @@ static int rpc_scan(rpc_ctx_t* ctx, char* fmt, ...)
switch(*fmt) {
case '*': /* start of optional parameters */
modifiers++;
- /* no other action needed, for xmlrpc params are treated as
- optionals anyway */
- break;
+ read++;
+ fmt++;
+ continue; /* do not advance ctx->act-param */
case 'b': /* Bool */
case 't': /* Date and time */
case 'd': /* Integer */
tirpi 2009/07/13 17:13:12 CEST
SER CVS Repository
Modified files:
cfg cfg_script.c cfg_struct.c
Log:
cfg framework: fix the group handles in the main process
(backport from GIT)
The main process does not have a local configuration,
it has access only to the config values that were set before
forking. As a result, the group handles cannot ponint to
the shared memory address because the shared memory block
may be freed later by one of the child processes. This problem
resulted sometimes in a core dump after the processes were killed
when the main process tried to access a variable from shared mem
which was no longer available.
Revision Changes Path
1.7 +1 -2 sip_router/cfg/cfg_script.c
http://cvs.berlios.de/cgi-bin/viewcvs.cgi/ser/sip_router/cfg/cfg_script.c.d…
1.13 +8 -6 sip_router/cfg/cfg_struct.c
http://cvs.berlios.de/cgi-bin/viewcvs.cgi/ser/sip_router/cfg/cfg_struct.c.d…
Module: sip-router
Branch: master
Commit: df8b1cf011e0ecf4c9f06578ddc6b991fd1444c4
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=df8b1cf…
Author: Miklos Tirpak <miklos(a)iptel.org>
Committer: Miklos Tirpak <miklos(a)iptel.org>
Date: Mon Jul 13 16:36:36 2009 +0200
cfg framework: fix the group handles in the main process
The main process does not have a local configuration,
it has access only to the config values that were set before
forking. As a result, the group handles cannot ponint to
the shared memory address because the shared memory block
may be freed later by one of the child processes. This problem
resulted sometimes in a core dump after the processes were killed
when the main process tried to access a variable from shared mem
which was no longer available.
---
cfg/cfg_script.c | 1 -
cfg/cfg_select.c | 9 +++++++++
cfg/cfg_struct.c | 12 +++++++-----
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/cfg/cfg_script.c b/cfg/cfg_script.c
index 39a4068..8804e40 100644
--- a/cfg/cfg_script.c
+++ b/cfg/cfg_script.c
@@ -143,7 +143,6 @@ error:
/* fix-up the dynamically declared group:
* - allocate memory for the arrays
* - set the values within the memory block
- * - notify the drivers about the new group
*/
int cfg_script_fixup(cfg_group_t *group, unsigned char *block)
{
diff --git a/cfg/cfg_select.c b/cfg/cfg_select.c
index 4374aa6..d8871ba 100644
--- a/cfg/cfg_select.c
+++ b/cfg/cfg_select.c
@@ -203,6 +203,10 @@ int select_cfg_var(str *res, select_t *s, struct sip_msg *msg)
/* use the module's handle to access the variable, so the variables
are read from the local config */
p = *(group->handle) + var->offset;
+ if (p == NULL)
+ return -1; /* The group is not yet ready.
+ * (Trying to read the value from the
+ * main process that has no local configuration) */
switch (CFG_VAR_TYPE(var)) {
case CFG_VAR_INT:
@@ -295,9 +299,14 @@ unsigned int read_cfg_var(struct cfg_read_handle *read_handle, void **val)
group = (cfg_group_t *)(read_handle->group);
var = (cfg_mapping_t *)(read_handle->var);
+
/* use the module's handle to access the variable, so the variables
are read from the local config */
p = *(group->handle) + var->offset;
+ if (p == NULL)
+ return 0; /* The group is not yet ready.
+ * (Trying to read the value from the
+ * main process that has no local configuration) */
switch (CFG_VAR_TYPE(var)) {
case CFG_VAR_INT:
diff --git a/cfg/cfg_struct.c b/cfg/cfg_struct.c
index 533228b..4f28dfe 100644
--- a/cfg/cfg_struct.c
+++ b/cfg/cfg_struct.c
@@ -194,21 +194,23 @@ int cfg_shmize(void)
/* clone the strings to shm mem */
if (cfg_shmize_strings(group)) goto error;
- /* copy the values to the new block,
- and update the module's handle */
+ /* copy the values to the new block */
memcpy(block->vars+group->offset, group->vars, group->size);
- *(group->handle) = block->vars+group->offset;
} else {
/* The group was declared with NULL values,
* we have to fix it up.
* The fixup function takes care about the values,
* it fills up the block */
if (cfg_script_fixup(group, block->vars+group->offset)) goto error;
- *(group->handle) = block->vars+group->offset;
- /* notify the drivers about the new config definition */
+ /* Notify the drivers about the new config definition.
+ * Temporary set the group handle so that the drivers have a chance to
+ * overwrite the default values. The handle must be reset after this
+ * because the main process does not have a local configuration. */
+ *(group->handle) = block->vars+group->offset;
cfg_notify_drivers(group->name, group->name_len,
group->mapping->def);
+ *(group->handle) = NULL;
}
}
/* try to fixup the selects that failed to be fixed-up previously */
Module: sip-router
Branch: master
Commit: f38774811308f3e33984fd1e7d1375f00202572f
URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=f387748…
Author: Miklos Tirpak <miklos(a)iptel.org>
Committer: Miklos Tirpak <miklos(a)iptel.org>
Date: Mon Jul 13 16:58:22 2009 +0200
cfg framework: readme correction
Documentation about how to read "foreign" config values is
corrected.
---
doc/cfg.txt | 18 ++++++++++--------
1 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/doc/cfg.txt b/doc/cfg.txt
index 93d2c77..548ef5d 100644
--- a/doc/cfg.txt
+++ b/doc/cfg.txt
@@ -169,13 +169,15 @@ cfg_get(foo, cfg_handle, p)
It is also possible to access the variables of other modules or the core in two
different ways:
-1) Include the header file of the other module/core that declares the cfg_group_*
-structure and the handle for it. Than use the handle of that module/core to access
+1) For the core: include the header file that declares the cfg_group_*
+structure and the handle for it. Than use the handle of the core to access
the variable:
-cfg_get(bar, cfg_handle_of_bar, j);
+#include "../../cfg_core.h"
+cfg_get(core, core_cfg, use_dst_blacklist)
-2) Access the variables by their group and variable name:
+2) For the core, module, or script: access the variables by their group
+and variable name:
#include "../../cfg/cfg_select.h"
@@ -195,15 +197,15 @@ static int mod_init(void)
}
int j;
-if ((cfg_read_var_int(&var_bar_j, &j)) < 0) { error... }
+if ((read_cfg_var_int(&var_bar_j, &j)) < 0) { error... }
or similarly,
str s;
-if ((cfg_read_var_str(&var_bar_j, &s)) < 0) { error... }
+if ((read_cfg_var_str(&var_bar_j, &s)) < 0) { error... }
2) is a bit slower than 1) because the first solution returns the pointer directly
-to the variable, but 2) supports also the variables declared in the script that are
-not known at compile time.
+to the variable, but 2) offers access also to the configuration of other modules
+and to the variables declared in the script that are not known at compile time.
3. Using the framework in the core
===============================================================================