You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/doc/tutorials/rpc/kamailio_rpc.xml

919 lines
33 KiB

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
[ <!ENTITY % local.common.attrib
"xmlns:xi CDATA #FIXED 'http://www.w3.org/2001/XInclude'">
<!ENTITY % docentities SYSTEM "../../docbook/entities.xml">
%docentities;
]>
<!-- Include general documentation entities -->
<section id="rpc.main" xmlns:xi="http://www.w3.org/2001/XInclude">
<!--
<sectioninfo>
<releaseinfo role="cvs">$Revision$</releaseinfo>
<pubdate role="cvs">$Date$</pubdate>
</sectioninfo>
-->
<title>
The Kamailio RPC Control Interface
</title>
<section id="rpc.overview">
<title>Overview of Operation</title>
<para>
The RPC (Remote Procedure Call) interface is an interface for
communicating with external applications. Using it an external
application can call a function or procedure that will be executed
inside Kamailio. Function parameters are supported as well as returning
multiple values as results.
</para>
<para>
By itself RPC consists of two APIs, one for defining RPC functions
in a transport independent way (called the rpc module api) and one
for implementing RPC transports.
</para>
<para>
The RPC transports are implemented by writting a RPC
transport module. The most used transport modules are
<ulink url='http://www.kamailio.org/docs/modules/devel/modules/ctl/ctl.html'>
<emphasis>ctl</emphasis>
</ulink>,
<ulink url='http://www.kamailio.org/docs/modules/devel/modules/xmlrpc/xmlrpc.html'>
<emphasis>xmlrpc</emphasis>
</ulink>
and
<ulink url='http://www.kamailio.org/docs/modules/devel/modules/jsonrpc-s/jsonrpc-s.html'>
<emphasis>jsonrpc-s</emphasis>
</ulink>.
</para>
<para>
ctl implements a proprietary fast and space efficient
RPC encoding over different protocols (unix sockets, UDP, TCP, fifo).
</para>
<para>
xmlrpc uses the de-facto XML-RPC standard encoding
(over HTTP TCP or TLS).
</para>
<para>
jsonrpc-s uses the de-facto JSON-RPC standard encoding
(over HTTP TCP or TLS).
</para>
<para>
For more information about the existing transport modules, please
refer to their documentation.
</para>
<para>
When writing a RPC procedure or function, one needs only use the
RPC API and it will work automatically with all the transports and
encodings. One needs only to load the desired RPC transport module
(e.g. xmlrpc).
</para>
<para>
The RPC interface (or API) was created in such a way that would allow
supporting XML-RPC (because XML-RPC is a de-facto standard), while in
the same time being very easy to use.
</para>
</section>
<section id="rpc.module_api">
<title>Module API</title>
<para>
Each module can export RPC functions just like it can export
parameters and functions to be called from the script. Whenever &kamailio;
receives an RPC request, it will search through the list of
exported RPC functions and the function with matching name will be
executed. A couple of essential RPC functions are also embedded into
the SIP server core.
</para>
<para>
This section gives a detailed overview of the whole RPC API. <xref
linkend="rpc.rpc_functions"/> describes the prototype and
conventions used in RPC functions. <xref linkend="rpc.data_types"/>
gives a detailed overview of available data types that can be used
in function parameters and return value. <xref
linkend="rpc.getting_parameters"/> describes functions of the RPC
API that can be used to retrieve parameters of the function, and
finally <xref linkend="rpc.creating_result"/> describes functions of
the API that can be used to build the result value that will be
sent in the reply to the caller.
</para>
<para>
The whole RPC API is described in header file
<filename>kamailio/rpc.h</filename>. This file defines the set
of functions that must be implemented by RPC transport modules, as
described in <xref linkend="rpc.new_transport"/>, prototypes of RPC
functions and structures used for the communication between RPC
transport modules and ordinary modules exporting RPC functions.
</para>
<section id="rpc.rpc_functions">
<title>RPC Functions</title>
<para>
RPC functions are standard C functions with the following
prototype:
<programlisting>
typedef void (*rpc_function_t)(rpc_t* rpc, void* ctx);
</programlisting>
RPC functions take two parameters, first parameter is a pointer
to rpc_t structure and the context. The rpc_t structure
contains references to all API functions available to the RPC
function as well as all data necessary to create the
response. RPC functions do not return any value, instead the
return value is created using functions from the context. The
motivation for this decision is the fact that RPC functions
should always return a response and even the API functions
called from RPC functions should have the possibility to
indicate an error (and should not rely on RPC functions doing so).
</para>
<para>
If no reply is sent explicitely, the RPC transport module will
automatically send a "success" reply (e.g. 200 OK for XML-RPC)
when the RPC function finishes.
If no values are added to the response, the reponse will be an
empty "success" reply (e.g. a 200 OK with empty body for
XML-RPC).
RPC API functions will automatically send an error reply upon a
failure.
</para>
<para>
Each RPC function has associated an array of documentation
strings. The purpose of the documentation strings is to give a
short overview of the function, accepted parameters, and format
of the reply. By convention the name of the documentation string
array is same as the name of the function with "_doc" suffix.
</para>
<para>
Each module containing RPC functions has to export all the
RPC functions to the &kamailio; core in order to make them visible to the RPC
transport modules.
The export process involves a <emphasis>rpc_export_t</emphasis>
structure (either by itself or in an array):
<programlisting>
<emphasis>
typedef struct rpc_export {
const char* name; /* Name of the RPC function (null terminated) */
rpc_function_t function; /* Pointer to the function */
const char** doc_str; /* Documentation strings, method signature and description */
unsigned int flags; /* Various flags, reserved for future use */
} rpc_export_t;
</emphasis>
</programlisting>
</para>
<para>
The <varname>flags</varname> attribute of the
<varname>rpc_export</varname> structure is reserved for future
use and is currently unused.
</para>
<para>
There are several ways of exporting the RPC functions to the &kamailio; core:
<itemizedlist>
<listitem><para>
register a null terminated array of rpc_export_t structures
using the <function>rpc_register_array()</function> function
(defined in rpc_lookup.h), from the module init function
(mod_init()). This is the <emphasis>recommended</emphasis>
method for all the new modules.
<example><title>usrloc RPC Exports Declaration</title>
<para>
The <varname>rpc_export_t</varname> array for the modules_s/usrloc
module looks like:
</para>
<programlisting>
<emphasis>
rpc_export_t ul_rpc[] = {
{"usrloc.statistics", rpc_stats, rpc_stats_doc, 0},
{"usrloc.delete_aor", rpc_delete_aor, rpc_delete_aor_doc, 0},
{"usrloc.delete_contact", rpc_delete_contact, rpc_delete_contact_doc, 0},
{"usrloc.dump", rpc_dump, rpc_dump_doc, 0},
{"usrloc.flush", rpc_flush, rpc_flush_doc, 0},
{"usrloc.add_contact", rpc_add_contact, rpc_add_contact_doc, 0},
{"usrloc.show_contacts", rpc_show_contacts, rpc_show_contacts_doc, 0},
{0, 0, 0, 0}
};
</emphasis>
</programlisting>
<para>
To register it from the module init function one would use
something similar to:
</para>
<programlisting>
if (rpc_register_array(ul_rpc) != 0) {
ERR("failed to register RPC commands\n");
return -1;
}
</programlisting>
</example>
</para></listitem>
<listitem><para>
register RPCs one by one using the
<function>rpc_register_function()</function>
(defined in rpc_lookup.h), from the module init function.
</para></listitem>
<listitem><para>
register a null terminated array of rpc_export_t structures
using the &kamailio; module interface SER_MOD_INTERFACE
For this purpose, the
<varname>module_exports</varname> structure of the &kamailio; module API
contains a new attribute called <varname>rpc_methods</varname>:
<programlisting>
struct module_exports {
char* name; /* null terminated module name */
cmd_export_t* cmds; /* null terminated array of the exported commands */
<emphasis>rpc_export_t* rpc_methods;</emphasis> /* null terminated array of exported rpc methods */
param_export_t* params; /* null terminated array of the exported module parameters */
init_function init_f; /* Initialization function */
response_function response_f; /* function used for responses */
destroy_function destroy_f; /* function called upon shutdown */
onbreak_function onbreak_f;
child_init_function init_child_f; /* function called by all processes after the fork */
};
</programlisting>
<varname>rpc_methods</varname> is a pointer to an array of
rpc_export_t structures. The last element of the array is a
bumper containing zeroes in all the attributes of the
structure. The following program listing shows the exported RPC
functions of the modules_s/usrloc module, using the rpc_export_t array
<emphasis>ul_rpc</emphasis> defined above, in the
rpc_register_array() example:
<example><title>usrloc Module Exports Declaration</title>
<programlisting>
struct module_exports exports = {
"usrloc",
cmds, /* Exported functions */
<emphasis>ul_rpc</emphasis>, /* RPC methods */
params, /* Export parameters */
mod_init, /* Module initialization function */
0, /* Response function */
destroy, /* Destroy function */
0, /* OnCancel function */
child_init /* Child initialization function */ };
</programlisting>
</example>
<note><para>
This mode works only with modules using the SER flavour module
interface. It does not work for &kamailio; modules and it
will probably not work for future sip-router modules. It is
safer and recommended to use instead the
<function>rpc_register_array()</function> function.
</para></note>
</para></listitem>
</itemizedlist>
</para>
<para>
By convention the name of every exported function consists of
two parts delimited by a dot. The first part is the name of the
module or &kamailio; subsystem this function belongs to. The second
part is the name of the function.
</para>
</section>
<section id="rpc.data_types">
<title>Data Types</title>
<para>
The RPC API defines several basic and one compound data type
that can be used in communication with the caller of RPC
functions. The RPC API uses formating strings to describe data
types. Each data type is described by exactly one character in
the formating string. For example, if an RPC function calls
function <function>add</function> of the RPC API and it passes
two parameters to it, the first one of type string and the
second one of type integer, the function parameters will look
like:
<programlisting>
add("sd", string_param, int_param);
</programlisting>
Character "s" in the formating string tells to the function
that the 2nd parameter should be interpreted as string,
character "d" in the formating string tells to the function
that the 3rd parameter should be interpreted as signed integer.
</para>
<formalpara>
<title>Integer</title>
<para>
Integer type represents a signed 32-bit
integer. Corresponding character in the formating string is
"d". This parameter can be stored in C-style variable with
type <varname>int</varname>.
</para>
</formalpara>
<formalpara>
<title>Float</title>
<para>
Float type represents a signed floating point
number. Corresponding character in the formating string is
"f". Data of this type can be stored in C-style variables
of type <varname>double</varname>.
</para>
</formalpara>
<formalpara>
<title>String</title>
<para>
String type represents a string of characters. The string
may contain zeroes. This data type is represented by two
characters in the formatting string, either "s" or "S". "s"
indicates to the conversion function that the result should
be stored in a variable of type <varname>char*</varname>
and it should be zero terminated. "S" indicates to the
conversion function that the result will be stored in
a variable of type <varname>str</varname> which contains
both the pointer to the beginning of the string and its
length.
</para>
</formalpara>
<formalpara>
<title>Structure</title>
<para>
Structure is the only compound data type currently defined
in the API. A structure is a collection of attributes. Each
attribute is identified using name (string) and each
attribute can be one of the basic data types, that
is integer, float, or string. Nesting of structures is not
allowed (in other words, structure attributes cannot be of
type struct again). Corresponding character in the
formatting string is "{".
</para>
</formalpara>
<formalpara>
<title>Optional parameters</title>
<para>
Optional parameters can be used, but only in the
<function>scan</function> function. For optional parameters the
<function>scan</function> function will not automatically generate
a rpc fault if the input ends. Note that in this case the
<function>scan</function> will still return a negative value
(minus the number of parameters successfully read).
Optional parameters can be marked in the format string by
preceding the first optional parameter type with a "*".
All the parameters following a "*" are considered to be optional.
For example for the format string "ds*dds", the last 3 parameters
(2 ints and a string) are optional.
</para>
</formalpara>
<table>
<title>Data Type Overview</title>
<tgroup cols="3">
<tbody>
<row rowsep="1">
<entry>Name</entry>
<entry>Formating String Char</entry>
<entry>C-Style Variable</entry>
</row>
<row>
<entry>Integer</entry>
<entry>d</entry>
<entry>int</entry>
</row>
<row>
<entry>Float</entry>
<entry>f</entry>
<entry>double</entry>
</row>
<row>
<entry>String</entry>
<entry>s</entry>
<entry>char*</entry>
</row>
<row>
<entry>String</entry>
<entry>S</entry>
<entry>str*</entry>
</row>
<row>
<entry>Optional modifier</entry>
<entry>*</entry>
<entry>marks all further parameters as optional</entry>
</row>
<row>
<entry>Autoconvert modifier</entry>
<entry>.</entry>
<entry>requires auto-conversion for the next parameter</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section id="rpc.getting_parameters">
<title>Getting Parameters</title>
<para>
Each RPC function call can contain parameters. Parameters have
no name, their meaning is determined by their position in the
parameter set.
<note>
<para>
You can pass all parameters to a function within a
structure if you want to make them position
independent. Then each parameter can be retrieved by
its name regardless of its position.
</para>
</note>
There are two functions in the RPC API that can be used to
obtain function call parameters: <function>scan</function> and
<function>struct_scan</function>.
</para>
<section id="rpc.scan">
<title><function>scan</function></title>
<para>
Function <function>scan</function> can be used to retrieve
parameters from the parameter set. The function accepts
variable number of parameters. The first parameter is the
formatting string that determines the type of the
parameters to be retrieved. Each parameter is represented by
exactly one parameter type character in the string.
The variable part of parameters must contain as many pointers to C
variables as there are formatting non-modifiers characters in the
formatting string.
<warning>
<para>
The function will crash if you fail to provide
enough parameters.
</para>
</warning>
</para>
<para>
Besides characters representing parameter types, the formatting
string can contain two special modifiers: "*" and ".". The
modifiers do not have a correspondent in the variable part of the
parameters.
</para>
<para>
The meaning of "*" modifier is that any further parameters
(defined by other type characters in the formatting string) are
optional (they can be missing in the input and no rpc fault will
automatically be generated).
</para>
<para>
The '.' modifiers turns on type autoconversion for the next
parameter. This means that if the type of the next parameter
differs from the type specified in the formatting string, the
parameter will be automatically converted to the formatting string
type (if possible) and if the automatic conversion succeeds, no
fault will be generated.
</para>
<para>
The function returns the number of parameters read on success
(a number greater or equal 0) and - (minus) the number of
parameters read on error (for example for an error after
reading 2 parameters it will return -2).
When a failure occurs (incorrect parameter type or no more
parameters in the parameter set) the function will
return a negative number (- number of parameters read so far)
and it will also automatically change the reply that will be
sent to the caller to indicate that a failure has occurred on
the server (unless the "*" is used and the error is lack
of more parameters).
</para>
<para>
The prototype of the function is:
<programlisting>
int scan((void* ctx, char* fmt, ...)
</programlisting>
It is possible to either call the function once to scan all
the parameters:
<programlisting>
rpc->scan(ctx, "sdf", &amp;string_val, &amp;int_val, &amp;double_val);
</programlisting>
Or you can call the same function several times and it will
continue where it left off previously:
<programlisting>
rpc->scan(ctx, "s", &amp;string_val);
rpc->scan(ctx, "d", &amp;int_val);
rpc->scan(ctx, "f", &amp;double_val);
</programlisting>
</para>
<para>
</para>
</section>
<section>
<title><function>struct_scan</function></title>
<para>
Function <function>struct_scan</function> can be used to
retrieve named attributes from a parameter of type
structure.
<note><para>
This function is obsolete and not implemented by all the
rpc transports (e.g.: ctl / binrpc). Consider using the normal
<function>scan</function> instead.
</para></note>
When retrieving a structure parameter from the
parameter set:
<programlisting>
rpc->scan(ctx, "{", &amp;handle);
</programlisting>
The corresponding variable (named
<varname>handle</varname> in the example above) will contain
the index of the structure parameter within the parameter
set, but the index cannot be used to retrieve the contents
of the structure. To retrieve the contents of the structure
you can use function <function>struct_scan</function>. The
function gets the handle as the first parameter:
<programlisting>
rpc->struct_scan(handle, "sd", "str_attr", &amp;str_val, "int_attr", &amp;int_val);
</programlisting>
The second parameter is the formatting string followed by
pairs of parameters. First parameter in each pair is the
name of the attribute to retrieve (string) and the second
parameter in each pair is the pointer to the variable to
store the value of the parameter. The function returns the
number of parameters (name value pairs) read on
success and - number of parameters read so far on an error
(just like the <function>scan</function> function). The function
also indicates an error if a requested attribute is missing in
the structure.
</para>
</section>
<section><title>Retrieving Parameters Example</title>
<example>
<title>Retrieving Parameters</title>
<programlisting>
<![CDATA[
static void rpc_delete_contact(rpc_t* rpc, void* ctx)
{
str aor, contact;
char* table;
void *handle;
int expires;
double q;
if (rpc->scan(ctx, "sS{", &table, &aor, &handle) < 0) {
/* Reply is set automatically by scan upon failure,
* no need to do anything here
*/
return;
}
if (rpc->struct_scan(handle, "Sdf", "Contact", &contact,
"Expires", &expires,
"Q", &q ) < 0) {
/* Reply is set automatically by struct_scan upon failure,
* no need to do anything here
*/
return;
}
/* Process retrieved parameters here */
}
/* variable number of parameters:
echo back all the parameters, string type required */
static void core_prints(rpc_t* rpc, void* c)
{
char* string = 0;
while((rpc->scan(c, "*s", &string)>0))
rpc->add(c, "s", string);
}
/* variable number of parameters and auto conversion:
echo back all the parameters, works with any type (everything is
internally converted to string, notice the '.' modifier) */
static void core_echo(rpc_t* rpc, void* c)
{
char* string = 0;
while((rpc->scan(c, "*.s", &string)>0))
rpc->add(c, "s", string);
}
]]>
</programlisting>
</example>
</section>
</section>
<section id="rpc.creating_result">
<title>Building Reply</title>
<para>
The RPC API contains several functions that can be used to
modify and/or send a reply. The functions use formatting
strings and parameter lists just like functions described in
<xref linkend="rpc.getting_parameters"/>.
</para>
<para>
Each RPC function call must return a reply. The reply can be
either a failure reply or success reply. Failure replies
contain only the status code and reason phrase. Success
replies can have arbitrary amount of data attached to
them. Status codes 3xx, 4xx, 5xx, and 6xx indicate
failures. Status code 2xx indicates success.
</para>
<para>
The default reply is 200 OK with no data attached to it. This
is what will be returned by the RPC transport module if you do
not call any of the reply-related functions described in this
section.
<example>
<title>Sending default reply</title>
<programlisting>
<![CDATA[
static void rpc_dummy(rpc_t* rpc, void *ctx)
{
/* 200 OK with no data will be returned */
}
]]>
</programlisting>
</example>
</para>
<section>
<title>fault</title>
<para>
You can use <function>fault</function> function to indicate
that an error has occurred on the server to the caller. The
function accepts two parameters. The first parameter is the
status code and the second parameter is the reason phrase.
<programlisting>
<![CDATA[
static void rpc_my_function(rpc_t* rpc, void *ctx)
{
rpc->fault(ctx, 600, "Not Yet Implemented");
}
]]>
</programlisting>
If your function first creates some result using
<function>add</function>, or <function>printf</function>
functions then all the data will be lost once you call
<function>fault</function> function. Failure replies must
not contain any data:
<programlisting>
<![CDATA[
static void rpc_my_function(rpc_t* rpc, void *ctx)
{
rpc->add(ctx, "s", "result1");
rpc->add(ctx, "d", variable);
/* Reply created by previous functions will be
* deleted and a failure reply 600 Not Yet Implemented
* will be created instead
*/
rpc->fault(ctx, 600, "Not Yet Implemented");
/* You can also add data here, but that will have no
* effect
*/
rpc->add(ctx, "s", "result2");
}
]]>
</programlisting>
Similarly you can also call <function>add</function> or
<function>printf</function> functions after calling
<function>fault</function>, in this case they will have no
effect:
<programlisting>
<![CDATA[
static void rpc_my_function(rpc_t* rpc, void *ctx)
{
rpc->fault(ctx, 600, "Not Yet Implemented");
/* You can also add data here, but that will have no
* effect and only 600 Not Yet Implemented will be returned
*/
rpc->add(ctx, "s", "result2");
}
]]>
</programlisting>
</para>
</section>
<section>
<title>send</title>
<para>
RPC functions can use function <function>send</function> to
explicitly send the reply. Each RPC function call generates
exactly one reply. No reply will be sent after the function
finishes if it already sent the reply using
<function>send</function> function explicitly. This
function is especially useful if the RPC function needs to
perform some (potentially destructive) actions after the
reply has been sent.
</para>
<example>
<title>Kill the server</title>
<programlisting>
<![CDATA[
static void core_kill(rpc_t* rpc, void *ctx)
{
int sig_no;
if (rpc->scan(ctx, "d", &sig_no) < 0) return;
rpc->send(ctx, ); /* First send a reply */
kill(0, sig_no); /* Then kill the server */
}
]]>
</programlisting>
</example>
</section>
<section>
<title>add</title>
<para>
Function <function>add</function> can be used to add
arbitrary data to the result set. Its parameters and use
are analogical to <function>scan</function> function
described in <xref linkend="rpc.scan"/>. The first
parameter of the function is the formatting string that
determines the types of additional parameters:
<programlisting>
<![CDATA[
static void rpc_func(rpc_t* rpc, void *ctx)
{
str str_result;
int int_result;
void *handle;
double float_result;
if (rpc->add(ctx, "Sdf{", &str_result, int_result, float_result, &handle) < 0) return;
}
]]>
</programlisting>
Naturally you can call this function several times, adding
only one piece of data at a time. The function returns 0 on
success and -1 on an error. In case of an error the reply
is set automatically with corresponding error code and
reason phrase.
</para>
<para>
The last character in the formatting string of the function
above indicates that the last data to be added will be a
structure. This deserves some clarification. In this case,
the function will create an empty structure and the handle
to the newly created structure will be stored in
<varname>handle</varname> variable (hence the last
parameter is pointer to an integer). In this particular
example parameters <varname>str_result</varname>,
<varname>int_result</varname>, and
<varname>float_result</varname> will be used for reading
while parameter <varname>handle</varname> will be used for
writing by the function.
</para>
<para>
You can set the attributes of the newly created structure
using <function>struct_add</function> function described in
<xref linkend="rpc.struct_add"/>.
</para>
</section>
<section>
<title>rpl_printf</title>
<para>
<varname>rpl_printf</varname> is a convenience function. The
function adds data of type string to the result set. The
first parameter of the function is again a formatting
string, but this time it is standard
<function>printf</function>-like formatting string:
<programlisting>
<![CDATA[
if (rpc->rpl_printf(ctx, "Unable to delete %d entries from table %s", num_entries, table_name) < 0) return;
]]>
</programlisting>
The return value of the function is the same as of
<function>add</function> function.
</para>
</section>
<section id="rpc.struct_add">
<title>struct_add</title>
<para>
Function <function>struct_add</function> can be used to add
attributes to a structure (created previously by
<function>add</function> function). The first parameter of
the function is handle obtained through
<function>add</function> function, the second parameters is
formatting string that determines the types of attributes
to be added. There must be two parameters per each
character in the formatting string, the first one is the
name of the attribute, the second parameter is the value
of the attribute. If a parameter with such a name already
exist in the structure then it will be overwritten with the
new value.
<programlisting>
<![CDATA[
static void rpc_func(rpc_t* rpc, void *ctx)
{
void *handle;
/* Create empty structure and obtain its handle */
if (rpc->add(ctx, "{", &handle) < 0) return;
/* Fill-in the structure */
if (rpc->struct_add(handle, "sd", "attr1", str_val,
"attr2", int_val ) < 0)
return;
}
]]>
</programlisting>
The function returns -1 on an error (and sets the status
code and reason phrase of the reply accordingly) and 0 on success.
</para>
</section>
</section>
<section>
<title>Real World Example</title>
<para>
The following example illustrates the use of most of the
functions from the API together:
</para>
<example>
<title>Real World Example RPC Function</title>
<programlisting>
<![CDATA[
static void rpc_register(rpc_t* rpc, void *ctx)
{
char* domain;
str aor;
contact_t contact, new_contact;
void *handle;
/* Extract the domain, address of record from the request */
if (rpc->scan(ctx, "sS{", &domain, &aor, &handle) < 0) return;
/* Extract the structure describing the contact to be processed */
if (rpc->struct_scan(handle, "Sdf", "Contact", &contact.c,
"Expires", &contact.expires,
"Q", &contact.q ) < 0)
return;
/* Process the contact, new_contact will contain updated value after processing */
if (process_contact(domain, &aor, &new_contact, &contact) < 0) {
/* Processing failed, indicate the failure to the caller */
rpc->fault(ctx, 500, "Error While Processing Contact");
return;
}
/* Return the domain and the address of record */
rpc->add(ctx, "sS{", &domain, &aor, &handle) < 0) return;
/* And also add the new values for contact, q, and expires parameters */
rpc->struct_add(handle, "Sdf", "Contact", &new_contact.c,
"Expires", &new_contact.expires,
"Q", &new_contact.q );
}
]]>
</programlisting>
</example>
</section>
</section>
<section id="rpc.client_examples">
<title>Client Examples</title>
<para>
<itemizedlist>
<listitem><para>
<emphasis>sercmd</emphasis> (C application that uses the
<emphasis>binrpc</emphasis> interface implemented by the
<emphasis>ctl</emphasis> module).
</para></listitem>
<listitem><para>
<emphasis>ser_ctl</emphasis> (python application that uses the
<emphasis>XML-RPC</emphasis> interface implemented by the
<emphasis>xmlrpc</emphasis>
module).
</para></listitem>
<listitem><para>
<emphasis>serweb</emphasis> (php application that can use
the <emphasis>XML-RPC</emphasis> interface to call ser
functions).
</para></listitem>
</itemizedlist>
</para>
</section>
<section id="rpc.new_transport">
<title>Implementing New Transports</title>
<remark>
To be done.
</remark>
<!-- TODO:
- create a new module
- take a look at sip_router/rpc.h
- implement all functions in that header field
- no garbage collection in rpc functions, the module needs to keep
track of all allocated data
- return value default to true
- parameter type conflict is an error
- missing struct attribute is an error
- always send a reply, prepare replies so that you do not have to
allocate memory at runtime
- str strings do not have to be zero terminated
- no structure/array nesting allowed
- printf creates string attribute
-->
<para>
Examples:
<itemizedlist>
<listitem><para>
<emphasis>ctl</emphasis>
</para></listitem>
<listitem><para>
<emphasis>xmlrpc</emphasis>
</para></listitem>
</itemizedlist>
</para>
</section>
<section id="rpc.xmlrpc_examples">
<title>Examples using xmlrpc</title>
<para>See the <varname>xmlrpc</varname> module documentation:
<ulink url='http://www.kamailio.org/docs/modules/devel/modules/xmlrpc.html'>modules/xmlrpc/README</ulink>.
</para>
</section>
</section>