$Revision$
$Date$
Extend select framework with module related functions
If you want to extend functions which select framework can call with some
dependent on module you have to follow next steps:
define working functions
create module's select parsing table
in module's mod_init call register_select_table
Define your working functions
Working functions are the piece of code, which is called as when SER needs
get result of select function (defined as @name.foo[2].bar[5]). The working copy
has following definition:
int select_function_name(str* res, struct select *s, struct sip_msg *msg)
Pointer to the string result workspace res, don't allocate
memory for the string, but use static buffer. There is no way to free the
allocated memory.
Pointer to the parsed select structure s. Holds all names,
numbers divided by the dot and square bracket notation. Use that if any of the
part used CONSUME_NEXT_STR or CONSUME_NEXT_INT to get the value.
Pointer to the processed message structure msg.
FIXUP CALL:
If you set FIXUP_CALL flag for the final
function, the fixup call will be done immediatelly after function resolution.
Such call is indicated with res==NULL && msg==NULL. Such call can convert any of
the select's parameter into internal data (can hold one pointer), if you do
that, set param_type to SEL_PARAM_DATA.
Result code of the function declares if the call was successful and if the result is
valid string or empty string.
-1 error
0 success, res contains non-empty string
1 success, result of select call is empty string (res can be left
unchanged)
Create module's select parsing table
Define static table of select_row_t type and initialize it directly.
The table is representation of tree (or oriented graph if you want), where
first column represents current (up-to now) resolved function (starting with NULL),
next two columns define if next parameter is integer or particullar string, next
column is new resolved function which will be tested in next round and the last
column is set of flags.
So in the previous example, the first line will accept syntax
@test and set the resolved function to select_test. In the
next round, all rows with the select_test in the first column will be used to
match, so the next two lines
are candidates to match depending on the next part of select syntax. If it
matches @test.value, the function is resolved to
select_test_val, if it matches @test.echo.anystring, it is
resolved into select_test_echo. Flag CONSUME_NEXT_STR will
accept any string at the 3rd position. As the OPTIONAL flag
is not present, it won't accept just the @test.echo syntax.
The table ends with the NULL in the 1st and 4th column,
other columns are not checked (the notation in the example suits well).
At the resolving time all function names must be already defined. For functions which are
not leaves, you can use macro ABSTRACT_F(name) to define empty
function, for working function you can use advance definition using
SELECT_F(name) macro.
Register the created table
In the module initialization function call register_select_table(table)
where table is the parsing tree/table you have defined in previous step.
This call ensures, that the table will become part of the parsing logic for
all select framework calls defined in the script file or called by another
module's parse_select.
NOTE: The tables are inserted into the beginning of the
list, so the core's table (and thus parseable names and definitions) can be
overrided by module's function, if it is defined with the same name. To
avoid such situation, the best practice is to start module's select with the
module's name. E.g in our example code both select functions start
with @test...
Example - module defining select extension
Example module test, which defines two select function.
@test.value - returns value passed as modules parameter
"value"
@test.echo.xxx - returns xxx regardless of what you put
as xxx (shows CONSUME_NEXT_STR option)
test.c
#include "../../sr_module.h"
#include "../../str.h"
#include "../../dprint.h"
#include "../../select.h"
MODULE_VERSION
static cmd_export_t cmds[] = {
{0, 0, 0, 0, 0}
};
static char* value=NULL;
static param_export_t params[] = {
{"value", STR_PARAM, &value},
{0, 0, 0}
};
int select_test_val(str* res, struct select* s, struct sip_msg* msg) {
DBG("SELECT_TEST_VAL called test_val=%s\n", value);
res->s=value;
res->len=strlen(value);
return 0;
}
int select_test_echo(str* res, struct select* s, struct sip_msg* msg) {
DBG("SELECT_TEST_ECHO called\n");
if (s->params[s->n-1].type==SEL_PARAM_STR) {
*res=s->params[s->n-1].v.s;
return 0;
} else
return -1;
}
ABSTRACT_F(select_test)
static select_row_t test_sel[] = {
{ NULL, SEL_PARAM_STR, STR_STATIC_INIT("test"), select_test, 0},
{ select_test, SEL_PARAM_STR, STR_STATIC_INIT("value"), select_test_val, 0},
{ select_test, SEL_PARAM_STR, STR_STATIC_INIT("echo"), select_test_echo, CONSUME_NEXT_STR},
{ NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
};
static int init(void) {
register_select_table(test_sel);
return 0;
};
struct module_exports exports = {
"test",
cmds, /* Exported commands */
0, /* RPC methods */
params, /* Exported parameters */
init, /* module initialization function */
0, /* response function*/
0, /* destroy function */
0, /* oncancel function */
0 /* per-child init function */
};
]]>